1 package club.wpia.gigi.testUtils;
3 import static org.junit.Assert.*;
5 import java.io.DataInputStream;
6 import java.io.DataOutputStream;
7 import java.io.IOException;
8 import java.net.Socket;
9 import java.net.SocketAddress;
11 import java.net.URLConnection;
12 import java.util.concurrent.LinkedBlockingQueue;
13 import java.util.concurrent.TimeUnit;
14 import java.util.regex.Matcher;
15 import java.util.regex.Pattern;
17 import club.wpia.gigi.email.EmailProvider;
18 import club.wpia.gigi.email.TestEmailProvider;
21 * This class reveives emails from the current system under test. It is the
22 * counterpart to the {@link TestEmailProvider} who is loaded into the system to
23 * intercept the emails. This class resides in the VM that executes the
24 * testcases and supplies the intercepted emails to the current test case.
26 public final class TestEmailReceiver extends EmailProvider implements Runnable, MailReceiver {
29 * An email that has been intercepted.
31 public static class TestMail {
41 public TestMail(String to, String subject, String message, String replyto) {
43 this.subject = subject;
44 this.message = message;
45 this.replyto = replyto;
48 public String getTo() {
52 public String getSubject() {
56 public String getMessage() {
60 public String getReplyto() {
64 public String extractLink() {
65 Pattern link = Pattern.compile("https?://[^\\s]+(?=\\s)");
66 Matcher m = link.matcher(getMessage());
71 public void verify() throws IOException {
72 String link = extractLink();
73 String[] parts = link.split("\\?");
74 URL u = new URL("https://" + ManagedTest.getServerName() + "/verify?" + parts[1]);
76 URLConnection csrfConn = u.openConnection();
77 String csrf = ManagedTest.getCSRF(csrfConn, 0);
79 u = new URL("https://" + ManagedTest.getServerName() + "/verify");
80 URLConnection uc = u.openConnection();
81 ManagedTest.cookie(uc, ManagedTest.stripCookie(csrfConn.getHeaderField("Set-Cookie")));
83 uc.getOutputStream().write((parts[1] + "&csrf=" + csrf).getBytes("UTF-8"));
85 uc.getInputStream().close();
89 public String toString() {
90 return "TestMail: " + subject + " for " + to;
96 private DataInputStream dis;
98 private DataOutputStream dos;
101 * Creates a new TestEmailReceiver based on the address where the
102 * {@link TestEmailProvider} is listening. This class is only ready after
103 * {@link #start()} has been called.
106 * the address where the {@link TestEmailProvider} is listening.
107 * @throws IOException
108 * if the connection cannot be opened
110 public TestEmailReceiver(SocketAddress target) throws IOException {
113 s.setKeepAlive(true);
114 s.setSoTimeout(1000 * 60 * 60);
115 dis = new DataInputStream(s.getInputStream());
116 dos = new DataOutputStream(s.getOutputStream());
121 * Spawns a new {@link Thread} that reads incoming {@link TestMail}s.
125 public void start() {
126 new Thread(this, "Mail receiver").start();
129 private LinkedBlockingQueue<TestMail> mails = new LinkedBlockingQueue<TestEmailReceiver.TestMail>();
132 * Retrieves an outgoing mail from the system. The method will return a
133 * {@link TestMail} or fail.
135 * @return The intercepted {@link TestMail}
139 public TestMail receive(String to) {
143 poll = mails.poll(60, TimeUnit.SECONDS);
145 } catch (InterruptedException e) {
146 throw new AssertionError("Interrupted while receiving mails");
149 throw new AssertionError("Mail receiving timed out");
152 assertEquals(to, poll.getTo());
159 * Retrieves an outgoing mail from the system or returns <code>null</code>
160 * if there was no mail sent in 30 seconds.
162 * @return The intercepted {@link TestMail} or <code>null</code> if no mail
166 public TestMail poll(String to) {
167 TestMail tm = mails.poll();
168 if (tm != null && to != null) {
169 assertEquals(to, tm.getTo());
178 String type = dis.readUTF();
179 if (type.equals("mail")) {
180 String to = dis.readUTF();
181 String subject = dis.readUTF();
182 String message = dis.readUTF();
183 String replyto = dis.readUTF();
184 mails.add(new TestMail(to, subject, message, replyto));
185 } else if (type.equals("challengeAddrBox")) {
186 String email = dis.readUTF();
187 dos.writeUTF(quickEmailCheck(email));
189 } else if (type.equals("ping")) {
191 System.err.println("Unknown type: " + type);
194 } catch (IOException e) {
202 private String quickEmailCheck(String email) throws IOException {
203 if (approveRegex.matcher(email).matches()) {
210 String error = "FAIL";
213 * Sets the error that will be sent back to incoming "fast mail checks" that
214 * only check for the availability of a mailbox.
217 * the error Massage to return in
218 * {@link EmailProvider#checkEmailServer(int, String)}
220 public void setEmailCheckError(String error) {
224 private Pattern approveRegex = Pattern.compile(".*");
227 * Specifies a pattern that will be used for incoming
228 * {@link EmailProvider#checkEmailServer(int, String)} calls to determine
229 * whether the mailbox should exist.
231 * @param approveRegex
232 * the regex that will perform the check
234 public void setApproveRegex(Pattern approveRegex) {
235 this.approveRegex = approveRegex;
239 * Removes all queued mails.
242 public void assertEmpty() {
243 int originalSize = mails.size();
245 assertEquals("test case should consume all produced emails", 0, originalSize);
249 * Resets this class to its initial state
251 * @see #assertEmpty()
252 * @see #setApproveRegex(Pattern)
253 * @see #setEmailCheckError(String)
255 public void reset() {
258 approveRegex = Pattern.compile(".*");
261 private boolean closed = false;
264 * stops reading for incoming messages
268 public void destroy() {
272 } catch (IOException e) {
278 public String checkEmailServer(int forUid, String address) throws IOException {
279 return quickEmailCheck(address);
283 public void sendMail(String to, String subject, String message, String replyto, String toname, String fromname, String errorsto, boolean extra) throws IOException {
284 mails.add(new TestMail(to, subject, message, replyto));