1 package org.cacert.gigi.testUtils;
3 import java.io.DataInputStream;
4 import java.io.DataOutputStream;
5 import java.io.IOException;
6 import java.net.Socket;
7 import java.net.SocketAddress;
9 import java.net.URLConnection;
10 import java.util.concurrent.LinkedBlockingQueue;
11 import java.util.concurrent.TimeUnit;
12 import java.util.regex.Matcher;
13 import java.util.regex.Pattern;
15 import org.cacert.gigi.email.EmailProvider;
16 import org.cacert.gigi.email.TestEmailProvider;
19 * This class reveives emails from the current system under test. It is the
20 * counterpart to the {@link TestEmailProvider} who is loaded into the system to
21 * intercept the emails. This class resides in the VM that executes the
22 * testcases and supplies the intercepted emails to the current test case.
24 public final class TestEmailReceiver extends EmailProvider implements Runnable {
27 * An email that has been intercepted.
29 public static class TestMail {
41 public TestMail(String to, String subject, String message, String from, String replyto) {
43 this.subject = subject;
44 this.message = message;
46 this.replyto = replyto;
49 public String getTo() {
53 public String getSubject() {
57 public String getMessage() {
61 public String getFrom() {
65 public String getReplyto() {
69 public String extractLink() {
70 Pattern link = Pattern.compile("https?://[^\\s]+(?=\\s)");
71 Matcher m = link.matcher(getMessage());
76 public void verify() throws IOException {
77 String link = extractLink();
78 String[] parts = link.split("\\?");
79 URL u = new URL("https://" + ManagedTest.getServerName() + "/verify?" + parts[1]);
81 URLConnection csrfConn = u.openConnection();
82 String csrf = ManagedTest.getCSRF(csrfConn, 0);
84 u = new URL("https://" + ManagedTest.getServerName() + "/verify");
85 URLConnection uc = u.openConnection();
86 ManagedTest.cookie(uc, ManagedTest.stripCookie(csrfConn.getHeaderField("Set-Cookie")));
88 uc.getOutputStream().write((parts[1] + "&csrf=" + csrf).getBytes("UTF-8"));
90 uc.getInputStream().close();
97 private DataInputStream dis;
99 private DataOutputStream dos;
102 * Creates a new TestEmailReceiver based on the address where the
103 * {@link TestEmailProvider} is listening. This class is only ready after
104 * {@link #start()} has been called.
107 * the address where the {@link TestEmailProvider} is listening.
108 * @throws IOException
109 * if the connection cannot be opened
111 public TestEmailReceiver(SocketAddress target) throws IOException {
114 s.setKeepAlive(true);
115 s.setSoTimeout(1000 * 60 * 60);
116 dis = new DataInputStream(s.getInputStream());
117 dos = new DataOutputStream(s.getOutputStream());
122 * Spawns a new {@link Thread} that reads incoming {@link TestMail}s.
126 public void start() {
127 new Thread(this, "Mail reciever").start();
130 private LinkedBlockingQueue<TestMail> mails = new LinkedBlockingQueue<TestEmailReceiver.TestMail>();
133 * Retrieves an outgoing mail from the system. The method will return a
134 * {@link TestMail} or fail.
136 * @return The intercepted {@link TestMail}
139 public TestMail receive() {
143 poll = mails.poll(60, TimeUnit.SECONDS);
145 } catch (InterruptedException e) {
146 throw new AssertionError("Interrupted while recieving mails");
149 throw new AssertionError("Mail recieving timed out");
156 * Retrieves an outgoing mail from the system or returns <code>null</code>
157 * if there was no mail sent in 30 seconds.
159 * @return The intercepted {@link TestMail} or <code>null</code> if no mail
163 public TestMail poll() {
171 String type = dis.readUTF();
172 if (type.equals("mail")) {
173 String to = dis.readUTF();
174 String subject = dis.readUTF();
175 String message = dis.readUTF();
176 String from = dis.readUTF();
177 String replyto = dis.readUTF();
178 mails.add(new TestMail(to, subject, message, from, replyto));
179 } else if (type.equals("challengeAddrBox")) {
180 String email = dis.readUTF();
181 dos.writeUTF(quickEmailCheck(email));
183 } else if (type.equals("ping")) {
185 System.err.println("Unknown type: " + type);
188 } catch (IOException e) {
196 private String quickEmailCheck(String email) throws IOException {
197 if (approveRegex.matcher(email).matches()) {
204 String error = "FAIL";
207 * Sets the error that will be sent back to incoming "fast mail checks" that
208 * only check for the availability of a mailbox.
211 * the error Massage to return in
212 * {@link EmailProvider#checkEmailServer(int, String)}
214 public void setEmailCheckError(String error) {
218 private Pattern approveRegex = Pattern.compile(".*");
221 * Specifies a pattern that will be used for incoming
222 * {@link EmailProvider#checkEmailServer(int, String)} calls to determine
223 * whether the mailbox should exist.
225 * @param approveRegex
226 * the regex that will perform the check
228 public void setApproveRegex(Pattern approveRegex) {
229 this.approveRegex = approveRegex;
233 * Removes all queued mails.
235 public void clearMails() {
240 * Resets this class to its initial state
243 * @see #setApproveRegex(Pattern)
244 * @see #setEmailCheckError(String)
246 public void reset() {
249 approveRegex = Pattern.compile(".*");
252 private boolean closed = false;
255 * stops reading for incoming messages
259 public void destroy() {
263 } catch (IOException e) {
269 public String checkEmailServer(int forUid, String address) throws IOException {
270 return quickEmailCheck(address);
274 public void sendmail(String to, String subject, String message, String from, String replyto, String toname, String fromname, String errorsto, boolean extra) throws IOException {
275 mails.add(new TestMail(to, subject, message, from, replyto));