Skip to content

Commit b901227

Browse files
author
subshell GmbH – Team Korora
authored
Testcontainer for mailhog
* Testcontainer for mailhog * Generalized methods * Javadoc, more convenience methods, more tests, ... * Javadoc in Model, more Tests, some refactoring * Typo in javadoc and trimmed headers
1 parent d9362fc commit b901227

File tree

4 files changed

+508
-0
lines changed

4 files changed

+508
-0
lines changed

modules/mailhog/build.gradle

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
description = "Testcontainers :: MailHog"
2+
3+
dependencies {
4+
compile project(':testcontainers')
5+
compile 'org.apache.httpcomponents:httpclient:4.5.8'
6+
compile 'org.apache.commons:commons-collections4:4.3'
7+
8+
testCompile 'com.sun.mail:javax.mail:1.6.0'
9+
testCompile 'org.apache.httpcomponents:httpcore:4.4.11'
10+
testCompile 'org.hamcrest:hamcrest-library:1.3'
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package org.testcontainers.containers;
2+
3+
import java.io.IOException;
4+
import java.net.URISyntaxException;
5+
import java.util.Arrays;
6+
import java.util.List;
7+
import java.util.Optional;
8+
9+
import org.apache.http.NameValuePair;
10+
import org.apache.http.client.utils.URIBuilder;
11+
import org.apache.http.message.BasicNameValuePair;
12+
import org.testcontainers.containers.model.Mail;
13+
14+
import com.fasterxml.jackson.databind.JsonNode;
15+
import com.fasterxml.jackson.databind.ObjectMapper;
16+
17+
/**
18+
* Testcontainer for MailHog (https://github.com/mailhog/MailHog) which is an email testing tool.
19+
* The docker image used is mailhog/mailhog.
20+
*
21+
* The internal http and smtp port of mailhog to use from other containers in the same docker
22+
* network are {@link #HTTP_PORT} and {@link #SMTP_PORT}.
23+
*/
24+
public class MailHogContainer extends GenericContainer<MailHogContainer> {
25+
26+
private static final String VERSION = "latest";
27+
28+
public static final int SMTP_PORT = 1025;
29+
public static final int HTTP_PORT = 8025;
30+
31+
private static final String ANY_ADDRESS = "0.0.0.0";
32+
private static final String MAILHOG_QUERY_PARAMETER_LIMIT = "limit";
33+
private static final String MAILHOG_QUERY_PARAMETER_KIND = "kind";
34+
private static final String MAILHOG_QUERY_PARAMETER_QUERY = "query";
35+
36+
public static final String MAIL_HEADER_SUBJECT = "Subject";
37+
public static final String MAIL_HEADER_DATE = "Date";
38+
public static final String MAIL_HEADER_TO = "To";
39+
public static final String MAIL_HEADER_CC = "Cc";
40+
41+
/**
42+
* Creates a test container with the latest available docker container for mailhog.
43+
*/
44+
public MailHogContainer() {
45+
this(VERSION);
46+
}
47+
48+
/**
49+
* Creates a test container for mailhog with the given version
50+
* @param version The version of the docker container for mailhog
51+
*/
52+
public MailHogContainer(String version) {
53+
super("mailhog/mailhog:" + version);
54+
withEnv("MH_SMTP_BIND_ADDR", ANY_ADDRESS + ":" + SMTP_PORT);
55+
withEnv("MH_UI_BIND_ADDR", ANY_ADDRESS + ":" + HTTP_PORT);
56+
withEnv("MH_API_BIND_ADDR", ANY_ADDRESS + ":" + HTTP_PORT);
57+
withExposedPorts(SMTP_PORT, HTTP_PORT);
58+
}
59+
60+
/**
61+
* Returns the external http endpoint
62+
* @return endpoint
63+
*/
64+
public String getHttpEndpoint() {
65+
return String.format("http://%s:%d", getContainerIpAddress(), getHttpPort());
66+
}
67+
68+
/**
69+
* Returns the external SMTP endpoint
70+
* @return endpoint
71+
*/
72+
public String getSmtpEndpoint() {
73+
return String.format("%s:%d", getContainerIpAddress(), getSmtpPort());
74+
}
75+
76+
/**
77+
* Returns the external http port
78+
* @return port
79+
*/
80+
public int getHttpPort() {
81+
return getMappedPort(HTTP_PORT);
82+
}
83+
84+
/**
85+
* Returns the external smtp port
86+
* @return port
87+
*/
88+
public int getSmtpPort() {
89+
return getMappedPort(SMTP_PORT);
90+
}
91+
92+
/**
93+
* @return all Mails
94+
* @throws IOException
95+
* @throws URISyntaxException
96+
*/
97+
public List<Mail> getAllMails() throws IOException, URISyntaxException {
98+
return getMails(Integer.MAX_VALUE);
99+
}
100+
101+
/**
102+
* Returns the newest Mails with the given limit
103+
* @param limit
104+
* @return
105+
* @throws IOException
106+
* @throws URISyntaxException
107+
*/
108+
public List<Mail> getMails(int limit) throws IOException, URISyntaxException {
109+
return getMailsWithParameters(new BasicNameValuePair(MAILHOG_QUERY_PARAMETER_LIMIT, Integer.toString(limit)));
110+
}
111+
112+
/**
113+
* Returns the newest Mails from specific sender with given limit
114+
* @param sender
115+
* @param limit
116+
* @return
117+
* @throws URISyntaxException
118+
* @throws IOException
119+
*/
120+
public List<Mail> getMailsFrom(String sender, int limit) throws URISyntaxException, IOException {
121+
return getMailsWithParameters(
122+
new BasicNameValuePair(MAILHOG_QUERY_PARAMETER_KIND, "from"),
123+
new BasicNameValuePair(MAILHOG_QUERY_PARAMETER_QUERY, sender),
124+
new BasicNameValuePair(MAILHOG_QUERY_PARAMETER_LIMIT, Integer.toString(limit))
125+
);
126+
}
127+
128+
/**
129+
* Returns the newest Mail from given sender
130+
* @param sender
131+
* @return optional of the mail, empty optional if no Mail from the sender is found
132+
* @throws URISyntaxException
133+
* @throws IOException
134+
*/
135+
public Optional<Mail> getNewestMailFrom(String sender) throws URISyntaxException, IOException {
136+
return getMailsFrom(sender, 1).stream().findFirst();
137+
}
138+
139+
/**
140+
* Returns all mails from given sender.
141+
* @param sender
142+
* @return
143+
* @throws IOException
144+
* @throws URISyntaxException
145+
*/
146+
public List<Mail> getAllMailsFrom(String sender) throws IOException, URISyntaxException {
147+
return getMailsFrom(sender, Integer.MAX_VALUE);
148+
}
149+
150+
/**
151+
* The mails queried with the given parameter
152+
* (see <a href="https://github.com/blueimp/mailhog/blob/master/docs/APIv2/swagger-2.0.yaml">swagger documentation of mailhog</a>)
153+
* @param parameters
154+
* @return list of mails
155+
* @throws URISyntaxException
156+
* @throws IOException
157+
*/
158+
public List<Mail> getMailsWithParameters(NameValuePair... parameters) throws URISyntaxException, IOException {
159+
ObjectMapper mapper = new ObjectMapper();
160+
161+
URIBuilder uri = new URIBuilder(getHttpEndpoint());
162+
163+
boolean isSearch = Arrays.stream(parameters)
164+
.map(NameValuePair::getName)
165+
.anyMatch(name -> Arrays.asList(MAILHOG_QUERY_PARAMETER_KIND, MAILHOG_QUERY_PARAMETER_QUERY).contains(name));
166+
167+
if (isSearch) {
168+
uri.setPath("/api/v2/search");
169+
} else {
170+
uri.setPath("/api/v2/messages");
171+
}
172+
173+
uri.setParameters(parameters);
174+
175+
JsonNode jsonNode = mapper.readTree(uri.build().toURL());
176+
return Arrays.asList(mapper.treeToValue(jsonNode.get("items"), Mail[].class));
177+
}
178+
179+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package org.testcontainers.containers.model;
2+
3+
import static org.testcontainers.containers.MailHogContainer.*;
4+
5+
import java.time.ZonedDateTime;
6+
import java.time.format.DateTimeFormatter;
7+
import java.util.ArrayList;
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.stream.Collectors;
12+
13+
import org.apache.commons.lang.StringUtils;
14+
15+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
16+
import com.fasterxml.jackson.annotation.JsonProperty;
17+
18+
import lombok.EqualsAndHashCode;
19+
import lombok.Getter;
20+
import lombok.Setter;
21+
import lombok.ToString;
22+
23+
/**
24+
* This model class represents an email.
25+
*/
26+
@Getter
27+
@Setter
28+
@JsonIgnoreProperties(ignoreUnknown = true)
29+
@EqualsAndHashCode
30+
@ToString
31+
public class Mail {
32+
33+
@JsonProperty("ID")
34+
private String id;
35+
36+
@JsonProperty("Content")
37+
private Content content;
38+
39+
@Getter
40+
@Setter
41+
@JsonIgnoreProperties(ignoreUnknown = true)
42+
@EqualsAndHashCode
43+
@ToString
44+
public static class Content {
45+
@JsonProperty("Headers")
46+
private Map<String, List<String>> headers;
47+
@JsonProperty("Body")
48+
private String body;
49+
}
50+
51+
/**
52+
* Returns the header with the name "Date".
53+
* @return the date
54+
*/
55+
public ZonedDateTime getDate() {
56+
List<String> date = content.getHeaders().get(MAIL_HEADER_DATE);
57+
return ZonedDateTime.parse(date.get(0).replaceFirst(" \\(.+\\)$", StringUtils.EMPTY), DateTimeFormatter.RFC_1123_DATE_TIME);
58+
}
59+
60+
/**
61+
* Returns the subject
62+
* @return the subject
63+
*/
64+
public String getSubject() {
65+
List<String> subjectList = content.getHeaders().get(MAIL_HEADER_SUBJECT);
66+
if (subjectList != null && !subjectList.isEmpty()) {
67+
return subjectList.get(0);
68+
} else {
69+
return StringUtils.EMPTY;
70+
}
71+
}
72+
73+
/**
74+
* Returns the receivers of the mail (header name To)
75+
* @return the receivers
76+
*/
77+
public List<String> getTo() {
78+
return getHeader(MAIL_HEADER_TO);
79+
}
80+
81+
/**
82+
* Returns the cc receivers of the mail (header name Cc)
83+
* @return the cc receivers
84+
*/
85+
public List<String> getCC() {
86+
return getHeader(MAIL_HEADER_CC);
87+
}
88+
89+
/**
90+
* Returns the header with given header name. If there are multiple entries with the same header name (i.e.
91+
* Received), each entry will result in an entry of the list. In case of multiple entries in one header name (i.e.
92+
* To or Cc) separated by comma, the entry will be split using the separator "," and trimmed afterwards.
93+
* @param headerName
94+
* @return the list of headers
95+
*/
96+
public List<String> getHeader(String headerName) {
97+
List<String> header = content.getHeaders().get(headerName);
98+
if (header != null && header.size() == 1) {
99+
return Arrays.stream(header.get(0).split(","))
100+
.map(StringUtils::trim)
101+
.collect(Collectors.toList());
102+
} else if(header != null && header.size() > 1) {
103+
return header;
104+
} else {
105+
return new ArrayList<>();
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)