org.wiremock.spring.internal.WireMockContextCustomizerFactory Maven / Gradle / Ivy
package org.wiremock.spring.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
import org.springframework.test.context.TestContextAnnotationUtils;
import org.wiremock.spring.ConfigureWireMock;
import org.wiremock.spring.EnableWireMock;
/**
* Creates {@link WireMockContextCustomizer} for test classes annotated with {@link EnableWireMock}.
*
* @author Maciej Walkowiak
*/
public class WireMockContextCustomizerFactory implements ContextCustomizerFactory {
static final ConfigureWireMock DEFAULT_CONFIGURE_WIREMOCK =
DefaultConfigureWireMock.class.getAnnotation(ConfigureWireMock.class);
@ConfigureWireMock(name = "wiremock")
private static class DefaultConfigureWireMock {}
static ConfigureWireMock[] getConfigureWireMocksOrDefault(
final ConfigureWireMock... configureWireMock) {
if (configureWireMock == null || configureWireMock.length == 0) {
return new ConfigureWireMock[] {WireMockContextCustomizerFactory.DEFAULT_CONFIGURE_WIREMOCK};
}
return configureWireMock;
}
@Override
public ContextCustomizer createContextCustomizer(
final Class> testClass, final List configAttributes) {
// scan class and all enclosing classes if the test class is @Nested
final ConfigureWiremockHolder holder = new ConfigureWiremockHolder();
this.parseDefinitions(testClass, holder);
if (holder.isEmpty()) {
return null;
} else {
return new WireMockContextCustomizer(holder.asArray());
}
}
private void parseDefinitions(final Class> testClass, final ConfigureWiremockHolder parser) {
parser.parse(testClass);
if (TestContextAnnotationUtils.searchEnclosingClass(testClass)) {
this.parseDefinitions(testClass.getEnclosingClass(), parser);
}
}
private static class ConfigureWiremockHolder {
private final List annotations = new ArrayList<>();
void add(final ConfigureWireMock... annotations) {
this.annotations.addAll(Arrays.asList(annotations));
this.sanityCheckDuplicateNames(this.annotations);
this.sanityCheckHttpOrHttpsMustBeEnabled(this.annotations);
this.sanityCheckHttpAndHttpsMustUseDifferentPorts(this.annotations);
this.sanityCheckUniquePorts(this.annotations);
}
void parse(final Class> clazz) {
final EnableWireMock annotation = AnnotationUtils.findAnnotation(clazz, EnableWireMock.class);
if (annotation != null) {
this.add(getConfigureWireMocksOrDefault(annotation.value()));
}
}
private void sanityCheckDuplicateNames(final List check) {
final List names = check.stream().map(it -> it.name()).toList();
final Set dublicateNames =
names.stream()
.filter(it -> Collections.frequency(names, it) > 1)
.collect(Collectors.toSet());
if (!dublicateNames.isEmpty()) {
throw new IllegalStateException(
"Names of mocks must be unique, found duplicates of: "
+ dublicateNames.stream().sorted().collect(Collectors.joining(",")));
}
}
private void sanityCheckHttpOrHttpsMustBeEnabled(final List check) {
for (final ConfigureWireMock configureWireMock : check) {
if (configureWireMock.port() == -1 && configureWireMock.httpsPort() == -1) {
throw new IllegalStateException(
"ConfigureWireMock "
+ configureWireMock.name()
+ " has both HTTP and HTTPS disabled. It is an invalid configuration.");
}
}
}
private void sanityCheckUniquePorts(final List check) {
final List ports =
check.stream().map(it -> List.of(it.port(), it.httpsPort())).toList().stream()
.collect(ArrayList::new, List::addAll, List::addAll);
final Set dublicatePors =
ports.stream()
.filter(it -> it > 0)
.filter(it -> Collections.frequency(ports, it) > 1)
.collect(Collectors.toSet());
if (!dublicatePors.isEmpty()) {
throw new IllegalStateException(
"Some statically configured ports are being used mor than once: "
+ dublicatePors.stream()
.sorted()
.map(it -> it.toString())
.collect(Collectors.joining(",")));
}
}
private void sanityCheckHttpAndHttpsMustUseDifferentPorts(final List check) {
for (final ConfigureWireMock configureWireMock : check) {
if (configureWireMock.port() > 0
&& configureWireMock.port() == configureWireMock.httpsPort()) {
throw new IllegalStateException(
"ConfigureWireMock "
+ configureWireMock.name()
+ " uses same port "
+ configureWireMock.port()
+ " for HTTP and HTTPS.");
}
}
}
boolean isEmpty() {
return this.annotations.isEmpty();
}
ConfigureWireMock[] asArray() {
return this.annotations.toArray(new ConfigureWireMock[] {});
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy