Skip to content

Commit 0c0d81a

Browse files
danijelmitarFameing
authored andcommitted
Add MailHog module (#1697)
1 parent 4edcc68 commit 0c0d81a

File tree

15 files changed

+437
-0
lines changed

15 files changed

+437
-0
lines changed

README.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ embedded:
342342

343343
=== link:embedded-wiremock/README.adoc[embedded-wiremock]
344344

345+
=== link:embedded-mailhog/README.adoc[embedded-mailhog]
346+
345347

346348
== How to contribute
347349

embedded-mailhog/README.adoc

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
=== embedded-mailhog
2+
3+
==== Maven dependency
4+
5+
.pom.xml
6+
[source,xml]
7+
----
8+
<dependency>
9+
<groupId>com.playtika.testcontainers</groupId>
10+
<artifactId>embedded-mailhog</artifactId>
11+
<scope>test</scope>
12+
</dependency>
13+
----
14+
15+
==== Consumes (via `bootstrap.properties`)
16+
17+
* `embedded.mailhog.enabled` `(true|false, default is true)`
18+
* `embedded.mailhog.reuseContainer` `(true|false, default is false)`
19+
* `embedded.mailhog.dockerImage` `(default is 'mailhog/mailhog:v1.0.1')`
20+
** Image versions on https://hub.docker.com/r/mailhog/mailhog/tags[dockerhub]
21+
* `embedded.mailhog.waitTimeoutInSeconds` `(default is 60 seconds)`
22+
* `embedded.mailhog.smtp-port` `(default is 1025)`
23+
* `embedded.mailhog.http-port` `(default is 8025)`
24+
* `embedded.toxiproxy.proxies.mailhog.enabled` Enables both creation of the container with ToxiProxy TCP proxy and a proxy to the `embedded-mailhog` container SMTP port.
25+
26+
27+
==== Produces
28+
29+
* `embedded.mailhog.host`
30+
* `embedded.mailhog.smtp-port`
31+
* `embedded.mailhog.http-port`
32+
* `embedded.mailhog.toxiproxy.host`
33+
* `embedded.mailhog.toxiproxy.port`
34+
* `embedded.mailhog.networkAlias`
35+
* `embedded.mailhog.internalSmtpPort`
36+
* `embedded.mailhog.internalHttpPort`
37+
* Bean `ToxiproxyContainer.ContainerProxy mailhogSmtpContainerProxy`
38+
39+
==== Example (Spring Boot)
40+
41+
bootstrap-test.yml
42+
[source,yaml]
43+
----
44+
embedded:
45+
mailhog:
46+
enabled: true
47+
docker-image: 'mailhog/mailhog:v1.0.1'
48+
----
49+
50+
application-test.yml
51+
[source,yaml]
52+
----
53+
spring:
54+
mail:
55+
host: ${embedded.mailhog.host}
56+
port: ${embedded.mailhog.smtp-port}
57+
----

embedded-mailhog/pom.xml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>testcontainers-spring-boot-parent</artifactId>
7+
<groupId>com.playtika.testcontainers</groupId>
8+
<version>3.1.1</version>
9+
<relativePath>../testcontainers-spring-boot-parent</relativePath>
10+
</parent>
11+
<modelVersion>4.0.0</modelVersion>
12+
13+
<artifactId>embedded-mailhog</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.playtika.testcontainers</groupId>
18+
<artifactId>testcontainers-common</artifactId>
19+
</dependency>
20+
<dependency>
21+
<groupId>com.playtika.testcontainers</groupId>
22+
<artifactId>embedded-toxiproxy</artifactId>
23+
</dependency>
24+
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-mail</artifactId>
28+
<scope>test</scope>
29+
<exclusions>
30+
<exclusion>
31+
<groupId>org.springframework.boot</groupId>
32+
<artifactId>spring-boot-starter-logging</artifactId>
33+
</exclusion>
34+
</exclusions>
35+
</dependency>
36+
</dependencies>
37+
38+
</project>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.playtika.testcontainer.mailhog;
2+
3+
import com.playtika.testcontainer.common.spring.DockerPresenceBootstrapConfiguration;
4+
import com.playtika.testcontainer.common.utils.ContainerUtils;
5+
import com.playtika.testcontainer.toxiproxy.condition.ConditionalOnToxiProxyEnabled;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.beans.factory.annotation.Qualifier;
8+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
10+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
11+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
12+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
13+
import org.springframework.context.annotation.Bean;
14+
import org.springframework.context.annotation.Configuration;
15+
import org.springframework.core.env.ConfigurableEnvironment;
16+
import org.springframework.core.env.MapPropertySource;
17+
import org.testcontainers.containers.GenericContainer;
18+
import org.testcontainers.containers.Network;
19+
import org.testcontainers.containers.ToxiproxyContainer;
20+
import org.testcontainers.containers.wait.strategy.Wait;
21+
22+
import java.util.LinkedHashMap;
23+
import java.util.Map;
24+
import java.util.Optional;
25+
26+
import static com.playtika.testcontainer.common.utils.ContainerUtils.configureCommonsAndStart;
27+
import static com.playtika.testcontainer.mailhog.MailHogProperties.BEAN_NAME_EMBEDDED_MAILHOG;
28+
29+
@Slf4j
30+
@Configuration
31+
@ConditionalOnExpression("${embedded.containers.enabled:true}")
32+
@AutoConfigureAfter(DockerPresenceBootstrapConfiguration.class)
33+
@ConditionalOnProperty(name = "embedded.mailhog.enabled", matchIfMissing = true)
34+
@EnableConfigurationProperties(MailHogProperties.class)
35+
public class EmbeddedMailHogBootstrapConfiguration {
36+
37+
private static final String MAILHOG_NETWORK_ALIAS = "mailhog.testcontainer.docker";
38+
39+
@Bean
40+
@ConditionalOnToxiProxyEnabled(module = "mailhog")
41+
ToxiproxyContainer.ContainerProxy mailhogSmtpContainerProxy(ToxiproxyContainer toxiproxyContainer,
42+
@Qualifier(BEAN_NAME_EMBEDDED_MAILHOG) GenericContainer<?> mailhogContainer,
43+
MailHogProperties properties,
44+
ConfigurableEnvironment environment) {
45+
ToxiproxyContainer.ContainerProxy proxy = toxiproxyContainer.getProxy(mailhogContainer, properties.getSmtpPort());
46+
47+
Map<String, Object> map = new LinkedHashMap<>();
48+
map.put("embedded.mailhog.smtp.toxiproxy.host", proxy.getContainerIpAddress());
49+
map.put("embedded.mailhog.smtp.toxiproxy.port", proxy.getProxyPort());
50+
map.put("embedded.mailhog.smtp.toxiproxy.proxyName", proxy.getName());
51+
52+
MapPropertySource propertySource = new MapPropertySource("embeddedMailhogSmtpToxiproxyInfo", map);
53+
environment.getPropertySources().addFirst(propertySource);
54+
log.info("Started MailHog SMTP ToxiProxy connection details {}", map);
55+
56+
return proxy;
57+
}
58+
59+
@ConditionalOnMissingBean(name = BEAN_NAME_EMBEDDED_MAILHOG)
60+
@Bean(name = BEAN_NAME_EMBEDDED_MAILHOG, destroyMethod = "stop")
61+
public GenericContainer<?> mailHog(ConfigurableEnvironment environment,
62+
MailHogProperties properties,
63+
Optional<Network> network) {
64+
GenericContainer<?> mailHog = new GenericContainer<>(ContainerUtils.getDockerImageName(properties))
65+
.withExposedPorts(properties.getSmtpPort(), properties.getHttpPort())
66+
.withNetworkAliases(MAILHOG_NETWORK_ALIAS)
67+
.waitingFor(Wait.forListeningPort());
68+
69+
network.ifPresent(mailHog::withNetwork);
70+
71+
mailHog = configureCommonsAndStart(mailHog, properties, log);
72+
registerMailHogEnvironment(mailHog, environment, properties);
73+
return mailHog;
74+
}
75+
76+
private void registerMailHogEnvironment(GenericContainer<?> mailHog, ConfigurableEnvironment environment, MailHogProperties properties) {
77+
Integer smtpMappedPort = mailHog.getMappedPort(properties.getSmtpPort());
78+
Integer httpMappedPort = mailHog.getMappedPort(properties.getHttpPort());
79+
80+
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
81+
map.put("embedded.mailhog.host", mailHog.getHost());
82+
map.put("embedded.mailhog.smtp-port", smtpMappedPort);
83+
map.put("embedded.mailhog.http-port", httpMappedPort);
84+
map.put("embedded.mailhog.networkAlias", MAILHOG_NETWORK_ALIAS);
85+
map.put("embedded.mailhog.internalSmtpPort", properties.getSmtpPort());
86+
map.put("embedded.mailhog.internalHttpPort", properties.getHttpPort());
87+
88+
log.info("Started MailHog. Connection details: {}", map);
89+
90+
MapPropertySource propertySource = new MapPropertySource("embeddedMailHogInfo", map);
91+
environment.getPropertySources().addFirst(propertySource);
92+
}
93+
94+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.playtika.testcontainer.mailhog;
2+
3+
import com.playtika.testcontainer.common.properties.CommonContainerProperties;
4+
import lombok.Data;
5+
import lombok.EqualsAndHashCode;
6+
import org.springframework.boot.context.properties.ConfigurationProperties;
7+
8+
@Data
9+
@EqualsAndHashCode(callSuper = true)
10+
@ConfigurationProperties("embedded.mailhog")
11+
public class MailHogProperties extends CommonContainerProperties {
12+
13+
public static final String BEAN_NAME_EMBEDDED_MAILHOG = "embeddedMailHog";
14+
15+
private Integer smtpPort = 1025;
16+
private Integer httpPort = 8025;
17+
18+
@Override
19+
public String getDefaultDockerImage() {
20+
// Please don`t remove this comment.
21+
// renovate: datasource=docker
22+
return "mailhog/mailhog:v1.0.1";
23+
}
24+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"groups": [
3+
{
4+
"name": "embedded.mailhog",
5+
"description": "Configuration properties related to embedded MailHog."
6+
}
7+
],
8+
"properties": [
9+
{
10+
"name": "embedded.mailhog.enabled",
11+
"type": "java.lang.Boolean",
12+
"defaultValue": "true"
13+
},
14+
{
15+
"name": "embedded.mailhog.docker-image",
16+
"type": "java.lang.String",
17+
"defaultValue": "mailhog/mailhog:v1.0.1"
18+
}
19+
],
20+
"hints": [
21+
{
22+
"name": "embedded.mailhog.enabled",
23+
"values": [
24+
{
25+
"value": "true",
26+
"description": "Enables configuration of MailHog server on startup."
27+
},
28+
{
29+
"value": "false",
30+
"description": "Disables configuration of MailHog server on startup."
31+
}
32+
]
33+
},
34+
{
35+
"name": "embedded.mailhog.docker-image",
36+
"values": [
37+
{
38+
"value": "mailhog/mailhog:v1.0.1",
39+
"description": "Default MailHog image. Ref https://hub.docker.com/r/mailhog/mailhog for further info."
40+
}
41+
]
42+
}
43+
]
44+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
2+
com.playtika.testcontainer.mailhog.EmbeddedMailHogBootstrapConfiguration
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.playtika.testcontainer.mailhog;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.springframework.boot.autoconfigure.AutoConfigurations;
5+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
6+
import org.testcontainers.containers.Container;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
class DisableMailHogTest {
11+
12+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
13+
.withConfiguration(
14+
AutoConfigurations.of(EmbeddedMailHogBootstrapConfiguration.class)
15+
);
16+
17+
@Test
18+
void contextLoads() {
19+
contextRunner
20+
.withPropertyValues(
21+
"embedded.mailhog.enabled=false"
22+
)
23+
.run((context) -> assertThat(context)
24+
.hasNotFailed()
25+
.doesNotHaveBean(Container.class));
26+
}
27+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.playtika.testcontainer.mailhog;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.springframework.boot.autoconfigure.AutoConfigurations;
5+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
6+
import org.testcontainers.containers.ToxiproxyContainer;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
class DisableToxiProxyTest {
11+
12+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
13+
.withConfiguration(AutoConfigurations.of(
14+
EmbeddedMailHogBootstrapConfiguration.class));
15+
16+
@Test
17+
void isNotEnabledByDefault() {
18+
contextRunner
19+
.withPropertyValues(
20+
)
21+
.run((context) -> assertThat(context)
22+
.hasNotFailed()
23+
.doesNotHaveBean(ToxiproxyContainer.ContainerProxy.class));
24+
}
25+
26+
@Test
27+
void shouldDisableToxiProxy() {
28+
contextRunner
29+
.withPropertyValues(
30+
"embedded.toxiproxy.proxies.mailhog.enabled=false"
31+
)
32+
.run(context -> assertThat(context)
33+
.hasNotFailed()
34+
.doesNotHaveBean(ToxiproxyContainer.ContainerProxy.class));
35+
}
36+
}

0 commit comments

Comments
 (0)