Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public class WireMockContainer extends GenericContainer<WireMockContainer> {
private final StringBuilder wireMockArgs;
private final Map<String, Stub> mappingStubs = new HashMap<>();
private final Map<String, MountableFile> mappingFiles = new HashMap<>();
private final Map<String, Extension> extensions = new HashMap<>();
private final Map<String, WireMockPlugin> plugins = new HashMap<>();
private boolean isBannerDisabled = true;

/**
Expand Down Expand Up @@ -169,28 +169,39 @@ public WireMockContainer withFileFromResource(String name, Class<?> resource, St
}

/**
* Add extension that will be loaded from the specified JAR file.
* @param id Unique ID of the extension, for logging purposes
* Add extension that will be loaded from the specified JAR files.
* In the internal engine, it will be handled as a single plugin.
* @param classNames Class names of the extension to be included
* @param jars JARs to be included into the container
* @return this instance
*/
public WireMockContainer withExtension(String id, Collection<String> classNames, Collection<File> jars) {
final Extension extension = new Extension(id);
extension.extensionClassNames.addAll(classNames);
extension.jars.addAll(jars);
extensions.put(id, extension);
return this;
public WireMockContainer withExtensions(Collection<String> classNames, Collection<File> jars) {
return withExtensions(WireMockPlugin.guessPluginId(classNames, jars), classNames, jars);
}

/**
* Add extension that will be loaded from the specified JAR files.
* In the internal engine, it will be handled as a single plugin.
* @param id Identifier top use
* @param classNames Class names of the extension to be included
* @param jars JARs to be included into the container
* @return this instance
*/
public WireMockContainer withExtensions(String id, Collection<String> classNames, Collection<File> jars) {
final WireMockPlugin extension = new WireMockPlugin(id)
.withExtensions(classNames)
.withJars(jars);
return withPlugin(extension);
}

/**
* Add extension that will be loaded from the specified directory with JAR files.
* @param id Unique ID of the extension, for logging purposes
* In the internal engine, it will be handled as a single plugin.
* @param classNames Class names of the extension to be included
* @param jarDirectory Directory that stores all JARs
* @return this instance
*/
public WireMockContainer withExtension(String id, Collection<String> classNames, File jarDirectory) {
public WireMockContainer withExtensions(Collection<String> classNames, File jarDirectory) {
final List<File> jarsInTheDirectory;
try (Stream<Path> walk = Files.walk(jarDirectory.toPath())) {
jarsInTheDirectory = walk
Expand All @@ -202,19 +213,28 @@ public WireMockContainer withExtension(String id, Collection<String> classNames,
throw new IllegalArgumentException("Cannot list JARs in the directory " + jarDirectory, e);
}

return withExtension(id, classNames, jarsInTheDirectory);
return withExtensions(classNames, jarsInTheDirectory);
}

/**
* Add extension that will be loaded from the classpath.
* This method can be used if the extension is a part of the WireMock bundle,
* or a Jar is already added via {@link #withExtension(String, Collection, Collection)}}
* @param id Unique ID of the extension, for logging purposes
* or a Jar is already added via {@link #withExtensions(Collection, Collection)}}.
* In the internal engine, it will be handled as a single plugin.
* @param className Class name of the extension
* @return this instance
*/
public WireMockContainer withExtension(String id, String className) {
return withExtension(id, Collections.singleton(className), Collections.emptyList());
public WireMockContainer withExtension(String className) {
return withExtensions(Collections.singleton(className), Collections.emptyList());
}

private WireMockContainer withPlugin(WireMockPlugin plugin) {
String pluginId = plugin.getPluginId();
if (plugins.containsKey(pluginId)) {
throw new IllegalArgumentException("The plugin is already included: " + pluginId);
}
plugins.put(pluginId, plugin);
return this;
}

public String getBaseUrl() {
Expand Down Expand Up @@ -245,10 +265,10 @@ protected void configure() {
}

final ArrayList<String> extensionClassNames = new ArrayList<>();
for (Map.Entry<String, Extension> entry : extensions.entrySet()) {
final Extension ext = entry.getValue();
extensionClassNames.addAll(ext.extensionClassNames);
for (File jar : ext.jars) {
for (Map.Entry<String, WireMockPlugin> entry : plugins.entrySet()) {
final WireMockPlugin ext = entry.getValue();
extensionClassNames.addAll(ext.getExtensionClassNames());
for (File jar : ext.getJars()) {
withCopyToContainer(MountableFile.forHostPath(jar.toPath()), EXTENSIONS_DIR + jar.getName());
}
}
Expand All @@ -275,13 +295,5 @@ public Stub(String name, String json) {
}
}

private static final class Extension {
final String id;
final List<File> jars = new ArrayList<>();
final List<String> extensionClassNames = new ArrayList<>();

public Extension(String id) {
this.id = id;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.wiremock.integrations.testcontainers;

import org.testcontainers.shaded.com.google.common.io.Files;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Random;

/**
* Unofficial notion of a WirteMock plugin.
* WireMock at the moment operates only on the extension level,
* and here we try to introduce a concept of a plugin that may span multiple JARs and extensions.
* {@link #extensionClassNames} may be empty for WireMock 3 that supports auto-loading
*/
/*package*/ class WireMockPlugin {
private final String pluginId;
private final List<File> jars = new ArrayList<>();
private final List<String> extensionClassNames = new ArrayList<>();

public WireMockPlugin(String id) {
this.pluginId = id;
}

public String getPluginId() {
return pluginId;
}

public WireMockPlugin withJars(Collection<File> jars) {
this.jars.addAll(jars);
return this;
}

public WireMockPlugin withJar(File jar) {
return withJars(Collections.singleton(jar));
}

public WireMockPlugin withExtensions(Collection<String> extensionClassNames) {
this.extensionClassNames.addAll(extensionClassNames);
return this;
}

public WireMockPlugin withExtension(String className) {
return withExtensions(Collections.singleton(className));
}

/**
* Get JARs associated with the extension
* @return List of JARs. Might be empty if the plugin/extension is a part of the WireMock core or already in the classpath
*/
public List<File> getJars() {
return jars;
}

/**
* Get the list of extensions. Might be empty in WireMock 3
* @return List of extension class names within the plugin
*/
public List<String> getExtensionClassNames() {
return extensionClassNames;
}

public static String guessPluginId(Collection<String> classNames, Collection<File> jars) {
File jar = jars.stream().findFirst().orElse(null);
if (jar != null) {
return Files.getNameWithoutExtension(jar.getName());
}

String className = classNames.stream().findFirst().orElse(null);
if (className != null && className.length() > 1) {
return className.substring(className.lastIndexOf('.') + 1);
}

return "plugin_" + Math.random(); // Double is fun, right? :)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class WireMockContainerExtensionTest {
.withLogConsumer(new Slf4jLogConsumer(LOGGER))
.withStartupTimeout(Duration.ofSeconds(60))
.withMapping("json-body-transformer", WireMockContainerExtensionTest.class, "json-body-transformer.json")
.withExtension("JSON Body Transformer",
.withExtensions("JSON Body Transformer",
Collections.singleton("com.ninecookies.wiremock.extensions.JsonBodyTransformer"),
Collections.singleton(Paths.get("target", "test-wiremock-extension", "wiremock-extensions-0.4.1-jar-with-dependencies.jar").toFile()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ class WireMockContainerExtensionsCombinationTest {
WireMockContainer wiremockServer = new WireMockContainer(WireMockContainer.WIREMOCK_2_LATEST)
.withLogConsumer(new Slf4jLogConsumer(LOGGER))
.withMapping("json-body-transformer", WireMockContainerExtensionsCombinationTest.class, "json-body-transformer.json")
.withExtension("Webhook",
.withExtensions("Webhook",
Collections.singleton("org.wiremock.webhooks.Webhooks"),
Collections.singleton(Paths.get("target", "test-wiremock-extension", "wiremock-webhooks-extension-2.35.0.jar").toFile()))
.withExtension("JSON Body Transformer",
.withExtensions("JSON Body Transformer",
Collections.singleton("com.ninecookies.wiremock.extensions.JsonBodyTransformer"),
Collections.singleton(Paths.get("target", "test-wiremock-extension", "wiremock-extensions-0.4.1-jar-with-dependencies.jar").toFile()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class WireMockContainerExtensionsWebhookTest {
.withLogConsumer(new Slf4jLogConsumer(LOGGER))
.withCliArg("--global-response-templating")
.withMapping("webhook-callback-template", WireMockContainerExtensionsWebhookTest.class, "webhook-callback-template.json")
.withExtension("Webhook",
.withExtensions("Webhook",
Collections.singleton("org.wiremock.webhooks.Webhooks"),
Collections.singleton(Paths.get("target", "test-wiremock-extension", "wiremock-webhooks-extension-2.35.0.jar").toFile()))
.withAccessToHost(true); // Force the host access mechanism
Expand Down