All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.dropwizard.testing.common.Resource Maven / Gradle / Ivy

There is a newer version: 5.0.0-alpha.4
Show newest version
package io.dropwizard.testing.common;

import com.codahale.metrics.MetricRegistry;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jakarta.rs.json.JacksonXmlBindJsonProvider;
import io.dropwizard.jackson.Jackson;
import io.dropwizard.jersey.validation.Validators;
import io.dropwizard.logging.common.BootstrapLogging;
import io.dropwizard.testing.junit5.ResourceExtension;
import jakarta.validation.Validator;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.WebTarget;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.servlet.ServletProperties;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.glassfish.jersey.test.TestProperties;
import org.glassfish.jersey.test.inmemory.InMemoryTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;

import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

import static java.util.Objects.requireNonNull;

public class Resource {

    /**
     * A {@link Resource} builder which enables configuration of a Jersey testing environment.
     */
    @SuppressWarnings("unchecked")
    public static class Builder> {

        private final Set> singletons = new HashSet<>();
        private final Set> providers = new HashSet<>();
        private final Map properties = new HashMap<>();
        private MetricRegistry metricRegistry = new MetricRegistry();
        private ObjectMapper mapper = Jackson.newObjectMapper();
        private Validator validator = Validators.newValidator();
        private Consumer clientConfigurator = c -> {
        };
        private TestContainerFactory testContainerFactory = new InMemoryTestContainerFactory();
        private boolean registerDefaultExceptionMappers = true;
        private boolean bootstrapLogging = true;

        public B setMapper(ObjectMapper mapper) {
            this.mapper = mapper;
            return (B) this;
        }

        public B setMetricRegistry(MetricRegistry metricRegistry) {
            this.metricRegistry = metricRegistry;
            return (B) this;
        }

        public B setValidator(Validator validator) {
            this.validator = validator;
            return (B) this;
        }

        public B setClientConfigurator(Consumer clientConfigurator) {
            this.clientConfigurator = clientConfigurator;
            return (B) this;
        }

        public B addResource(Object resource) {
            return addResource(() -> resource);
        }

        public B addResource(Supplier resourceSupplier) {
            singletons.add(resourceSupplier);
            return (B) this;
        }

        public B addProvider(Class klass) {
            providers.add(klass);
            return (B) this;
        }

        public B addProvider(Supplier providerSupplier) {
            singletons.add(providerSupplier);
            return (B) this;
        }

        public B addProvider(Object provider) {
            return addProvider(() -> provider);
        }

        public B addProperty(String property, Object value) {
            properties.put(property, value);
            return (B) this;
        }

        public B setTestContainerFactory(TestContainerFactory factory) {
            this.testContainerFactory = factory;
            return (B) this;
        }

        public B setRegisterDefaultExceptionMappers(boolean value) {
            registerDefaultExceptionMappers = value;
            return (B) this;
        }

        public B bootstrapLogging(boolean value) {
            bootstrapLogging = value;
            return (B) this;
        }

        /**
         * Builds a {@link Resource} with a configured Jersey testing environment.
         *
         * @return a new {@link Resource}
         */
        protected Resource buildResource() {
            if (bootstrapLogging) {
                BootstrapLogging.bootstrap();
            }
            Consumer extendedConfigurator = config -> {
                clientConfigurator.accept(config);
                config.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
            };
            return new Resource(new ResourceTestJerseyConfiguration(
                    singletons, providers, properties, mapper, metricRegistry, validator,
                    extendedConfigurator, testContainerFactory, registerDefaultExceptionMappers));
        }
    }

    /**
     * Creates a new Jersey testing environment builder for {@link ResourceExtension}
     *
     * @return a new {@link ResourceExtension.Builder}
     */
    public static ResourceExtension.Builder builder() {
        return new ResourceExtension.Builder();
    }

    private ResourceTestJerseyConfiguration configuration;

    @Nullable
    private JerseyTest test;

    private Resource(ResourceTestJerseyConfiguration configuration) {
        this.configuration = configuration;
    }

    public Validator getValidator() {
        return configuration.validator;
    }

    public ObjectMapper getObjectMapper() {
        return configuration.mapper;
    }

    public Consumer getClientConfigurator() {
        return configuration.clientConfigurator;
    }

    /**
     * Creates a web target to be sent to the resource under testing.
     *
     * @param path relative path (from tested application base URI) this web target should point to.
     * @return the created JAX-RS web target.
     */
    public WebTarget target(String path) {
        return getJerseyTest().target(path);
    }

    /**
     * Returns the pre-configured {@link Client} for this test. For sending
     * requests prefer {@link #target(String)}
     *
     * @return the {@link JerseyTest} configured {@link Client}
     */
    public Client client() {
        return getJerseyTest().client();
    }

    /**
     * Returns the underlying {@link JerseyTest}. For sending requests prefer
     * {@link #target(String)}.
     *
     * @return the underlying {@link JerseyTest}
     */
    public JerseyTest getJerseyTest() {
        return requireNonNull(test);
    }

    public void before() throws Throwable {
        DropwizardTestResourceConfig.CONFIGURATION_REGISTRY.put(configuration.getId(), configuration);

        test = new JerseyTest(configuration.testContainerFactory) {
            @Override
            protected URI getBaseUri() {
                forceSet(TestProperties.CONTAINER_PORT, "0");

                return super.getBaseUri();
            }

            @Override
            protected DeploymentContext configureDeployment() {
                return ServletDeploymentContext.builder(new DropwizardTestResourceConfig(configuration))
                        .initParam(ServletProperties.JAXRS_APPLICATION_CLASS,
                                DropwizardTestResourceConfig.class.getName())
                        .initParam(DropwizardTestResourceConfig.CONFIGURATION_ID, configuration.getId())
                        .build();
            }

            @Override
            protected void configureClient(ClientConfig clientConfig) {
                final JacksonXmlBindJsonProvider jsonProvider = new JacksonXmlBindJsonProvider();
                jsonProvider.setMapper(configuration.mapper);
                configuration.clientConfigurator.accept(clientConfig);
                clientConfig.register(jsonProvider);
            }
        };
        test.setUp();
    }

    public void after() throws Throwable {
        DropwizardTestResourceConfig.CONFIGURATION_REGISTRY.remove(configuration.getId());
        requireNonNull(test).tearDown();
    }
}