io.dropwizard.testing.junit.DropwizardAppRule Maven / Gradle / Ivy
The newest version!
package io.dropwizard.testing.junit;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.dropwizard.configuration.ConfigurationSourceProvider;
import io.dropwizard.core.Application;
import io.dropwizard.core.Configuration;
import io.dropwizard.core.cli.Command;
import io.dropwizard.core.cli.ServerCommand;
import io.dropwizard.core.setup.Environment;
import io.dropwizard.jersey.jackson.JacksonFeature;
import io.dropwizard.lifecycle.Managed;
import io.dropwizard.testing.ConfigOverride;
import io.dropwizard.testing.DropwizardTestSupport;
import jakarta.ws.rs.client.Client;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.junit.rules.ExternalResource;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
//@formatter:off
/**
* A JUnit rule for starting and stopping your application at the start and end of a test class.
*
* By default, the {@link Application} will be constructed using reflection to invoke the nullary
* constructor. If your application does not provide a public nullary constructor, you will need to
* override the {@link #newApplication()} method to provide your application instance(s).
*
*
*
* Using DropwizardAppRule at the suite level can speed up test runs, as the application is only started and stopped
* once for the entire suite:
*
*
*
* @RunWith(Suite.class)
* @SuiteClasses({FooTest.class, BarTest.class})
* public class MySuite {
* @ClassRule
* public static final DropwizardAppRule<MyConfig> DROPWIZARD = new DropwizardAppRule<>(...);
* }
*
*
*
* If the same instance of DropwizardAppRule is reused at the suite- and class-level, then the application will be
* started and stopped once, regardless of whether the entire suite or a single test is executed.
*
*
*
*
* public class FooTest {
* @ClassRule public static final DropwizardAppRule<MyConfig> DROPWIZARD = MySuite.DROPWIZARD;
*
* public void testFoo() { ... }
* }
*
* public class BarTest {
* @ClassRule public static final DropwizardAppRule<MyConfig> DROPWIZARD = MySuite.DROPWIZARD;
*
* public void testBar() { ... }
* }
*
*
*
* @param the configuration type
*/
//@formatter:on
public class DropwizardAppRule extends ExternalResource {
private static final int DEFAULT_CONNECT_TIMEOUT_MS = 1000;
private static final int DEFAULT_READ_TIMEOUT_MS = 5000;
private final DropwizardTestSupport testSupport;
private final AtomicInteger recursiveCallCount = new AtomicInteger(0);
@Nullable
private Client client;
public DropwizardAppRule(Class extends Application> applicationClass) {
this(applicationClass, (String) null);
}
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
ConfigOverride... configOverrides) {
this(applicationClass, configPath, (String) null, configOverrides);
}
/**
* @since 2.0
*/
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
ConfigurationSourceProvider configSourceProvider,
ConfigOverride... configOverrides) {
this(applicationClass, configPath, configSourceProvider, null, configOverrides);
}
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
Optional customPropertyPrefix,
ConfigOverride... configOverrides) {
this(applicationClass, configPath, customPropertyPrefix.orElse(null), configOverrides);
}
/**
* @since 2.0
*/
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
@Nullable String customPropertyPrefix,
ConfigOverride... configOverrides) {
this(applicationClass, configPath, customPropertyPrefix, ServerCommand::new, configOverrides);
}
/**
* @since 2.0
*/
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
ConfigurationSourceProvider configSourceProvider,
@Nullable String customPropertyPrefix,
ConfigOverride... configOverrides) {
this(applicationClass, configPath, configSourceProvider, customPropertyPrefix, ServerCommand::new, configOverrides);
}
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
Optional customPropertyPrefix,
Function, Command> commandInstantiator,
ConfigOverride... configOverrides) {
this(applicationClass, configPath, customPropertyPrefix.orElse(null), commandInstantiator, configOverrides);
}
/**
* @since 2.0
*/
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
@Nullable String customPropertyPrefix,
Function,
Command> commandInstantiator,
ConfigOverride... configOverrides) {
this(new DropwizardTestSupport<>(applicationClass, configPath, customPropertyPrefix, commandInstantiator, configOverrides));
}
/**
* @since 2.0
*/
public DropwizardAppRule(Class extends Application> applicationClass,
@Nullable String configPath,
ConfigurationSourceProvider configSourceProvider,
@Nullable String customPropertyPrefix,
Function,
Command> commandInstantiator,
ConfigOverride... configOverrides) {
this(new DropwizardTestSupport<>(applicationClass, configPath, configSourceProvider, customPropertyPrefix, commandInstantiator, configOverrides));
}
/**
* Alternate constructor that allows specifying exact Configuration object to
* use, instead of reading a resource and binding it as Configuration object.
*
* @since 0.9
*/
public DropwizardAppRule(Class extends Application> applicationClass,
C configuration) {
this(new DropwizardTestSupport<>(applicationClass, configuration));
}
/**
* Alternate constructor that allows specifying the command the Dropwizard application is started with.
*
* @since 1.1.0
*/
public DropwizardAppRule(Class extends Application> applicationClass,
C configuration, Function, Command> commandInstantiator) {
this(new DropwizardTestSupport<>(applicationClass, configuration, commandInstantiator));
}
public DropwizardAppRule(DropwizardTestSupport testSupport) {
this.testSupport = testSupport;
}
public DropwizardAppRule addListener(final ServiceListener listener) {
this.testSupport.addListener(new DropwizardTestSupport.ServiceListener() {
@Override
public void onRun(C configuration, Environment environment, DropwizardTestSupport rule) throws Exception {
listener.onRun(configuration, environment, DropwizardAppRule.this);
}
@Override
public void onStop(DropwizardTestSupport rule) throws Exception {
listener.onStop(DropwizardAppRule.this);
}
});
return this;
}
public DropwizardAppRule manage(final Managed managed) {
return addListener(new ServiceListener() {
@Override
public void onRun(C configuration, Environment environment, DropwizardAppRule rule) throws Exception {
environment.lifecycle().manage(managed);
}
});
}
@Override
protected void before() throws Exception {
if (recursiveCallCount.getAndIncrement() == 0) {
testSupport.before();
}
}
@Override
protected void after() {
if (recursiveCallCount.decrementAndGet() == 0) {
testSupport.after();
synchronized (this) {
if (client != null) {
client.close();
}
}
}
}
public C getConfiguration() {
return testSupport.getConfiguration();
}
public int getLocalPort() {
return testSupport.getLocalPort();
}
public int getPort(int connectorIndex) {
return testSupport.getPort(connectorIndex);
}
public int getAdminPort() {
return testSupport.getAdminPort();
}
public Application newApplication() {
return testSupport.newApplication();
}
@SuppressWarnings({"TypeParameterUnusedInFormals"})
public > A getApplication() {
return testSupport.getApplication();
}
public Environment getEnvironment() {
return testSupport.getEnvironment();
}
public ObjectMapper getObjectMapper() {
return testSupport.getObjectMapper();
}
public abstract static class ServiceListener {
public void onRun(T configuration, Environment environment, DropwizardAppRule rule) throws Exception {
// Default NOP
}
public void onStop(DropwizardAppRule rule) throws Exception {
// Default NOP
}
}
public DropwizardTestSupport getTestSupport() {
return testSupport;
}
/**
* Returns a new HTTP Jersey {@link Client} for performing HTTP requests against the tested
* Dropwizard server. The client can be reused across different tests and automatically
* closed along with the server. The client can be augmented by overriding the
* {@link #clientBuilder()} method.
*
* @return a new {@link Client} managed by the rule.
*/
public Client client() {
synchronized (this) {
if (client == null) {
client = clientBuilder().build();
}
return client;
}
}
protected JerseyClientBuilder clientBuilder() {
return new JerseyClientBuilder()
.register(new JacksonFeature(getObjectMapper()))
.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_CONNECT_TIMEOUT_MS)
.property(ClientProperties.READ_TIMEOUT, DEFAULT_READ_TIMEOUT_MS)
.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy