]> WPIA git - gigi.git/blob - tests/org/cacert/gigi/testUtils/TestEmailReceiver.java
2dd230cb308ed766fa8c98a1d2e8dd354aa207d1
[gigi.git] / tests / org / cacert / gigi / testUtils / TestEmailReceiver.java
1 package org.cacert.gigi.testUtils;
2
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;
8 import java.net.URL;
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;
14
15 import org.cacert.gigi.email.EmailProvider;
16 import org.cacert.gigi.email.TestEmailProvider;
17
18 /**
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.
23  */
24 public final class TestEmailReceiver extends EmailProvider implements Runnable {
25
26     /**
27      * An email that has been intercepted.
28      */
29     public class TestMail {
30
31         String to;
32
33         String subject;
34
35         String message;
36
37         String from;
38
39         String replyto;
40
41         public TestMail(String to, String subject, String message, String from, String replyto) {
42             this.to = to;
43             this.subject = subject;
44             this.message = message;
45             this.from = from;
46             this.replyto = replyto;
47         }
48
49         public String getTo() {
50             return to;
51         }
52
53         public String getSubject() {
54             return subject;
55         }
56
57         public String getMessage() {
58             return message;
59         }
60
61         public String getFrom() {
62             return from;
63         }
64
65         public String getReplyto() {
66             return replyto;
67         }
68
69         public String extractLink() {
70             Pattern link = Pattern.compile("https?://[^\\s]+(?=\\s)");
71             Matcher m = link.matcher(getMessage());
72             m.find();
73             return m.group(0);
74         }
75
76         public void verify() throws IOException {
77             String[] parts = extractLink().split("\\?");
78             URL u = new URL("https://" + ManagedTest.getServerName() + "/verify?" + parts[1]);
79
80             URLConnection csrfConn = u.openConnection();
81             String csrf = ManagedTest.getCSRF(csrfConn, 0);
82
83             u = new URL("https://" + ManagedTest.getServerName() + "/verify");
84             URLConnection uc = u.openConnection();
85             ManagedTest.cookie(uc, ManagedTest.stripCookie(csrfConn.getHeaderField("Set-Cookie")));
86             uc.setDoOutput(true);
87             uc.getOutputStream().write((parts[1] + "&csrf=" + csrf).getBytes("UTF-8"));
88             uc.connect();
89             uc.getInputStream().close();
90         }
91
92     }
93
94     private Socket s;
95
96     private DataInputStream dis;
97
98     private DataOutputStream dos;
99
100     /**
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.
104      * 
105      * @param target
106      *            the address where the {@link TestEmailProvider} is listening.
107      * @throws IOException
108      *             if the connection cannot be opened
109      */
110     public TestEmailReceiver(SocketAddress target) throws IOException {
111         s = new Socket();
112         s.connect(target);
113         s.setKeepAlive(true);
114         s.setSoTimeout(1000 * 60 * 60);
115         dis = new DataInputStream(s.getInputStream());
116         dos = new DataOutputStream(s.getOutputStream());
117         setInstance(this);
118     }
119
120     /**
121      * Spawns a new {@link Thread} that reads incoming {@link TestMail}s.
122      * 
123      * @see #destroy()
124      */
125     public void start() {
126         new Thread(this, "Mail reciever").start();
127     }
128
129     private LinkedBlockingQueue<TestMail> mails = new LinkedBlockingQueue<TestEmailReceiver.TestMail>();
130
131     /**
132      * Retrieves an outgoing mail from the system. The method will return a
133      * {@link TestMail} or fail.
134      * 
135      * @return The intercepted {@link TestMail}
136      * @see #poll()
137      */
138     public TestMail receive() {
139         TestMail poll;
140
141         try {
142             poll = mails.poll(60, TimeUnit.SECONDS);
143
144         } catch (InterruptedException e) {
145             throw new AssertionError("Interrupted while recieving mails");
146         }
147         if (poll == null) {
148             throw new AssertionError("Mail recieving timed out");
149         }
150
151         return poll;
152     }
153
154     /**
155      * Retrieves an outgoing mail from the system or returns <code>null</code>
156      * if there was no mail sent in 30 seconds.
157      * 
158      * @return The intercepted {@link TestMail} or <code>null</code> if no mail
159      *         has been sent.
160      * @see #receive()
161      */
162     public TestMail poll() {
163         try {
164             return mails.poll(60, TimeUnit.SECONDS);
165
166         } catch (InterruptedException e) {
167             throw new AssertionError("Interrupted while recieving mails");
168         }
169     }
170
171     @Override
172     public void run() {
173         try {
174             while (true) {
175                 String type = dis.readUTF();
176                 if (type.equals("mail")) {
177                     String to = dis.readUTF();
178                     String subject = dis.readUTF();
179                     String message = dis.readUTF();
180                     String from = dis.readUTF();
181                     String replyto = dis.readUTF();
182                     mails.add(new TestMail(to, subject, message, from, replyto));
183                 } else if (type.equals("challengeAddrBox")) {
184                     String email = dis.readUTF();
185                     dos.writeUTF(quickEmailCheck(email));
186                     dos.flush();
187                 } else if (type.equals("ping")) {
188                 } else {
189                     System.err.println("Unknown type: " + type);
190                 }
191             }
192         } catch (IOException e) {
193             if ( !closed) {
194                 e.printStackTrace();
195             }
196         }
197
198     }
199
200     private String quickEmailCheck(String email) throws IOException {
201         if (approveRegex.matcher(email).matches()) {
202             return "OK";
203         } else {
204             return error;
205         }
206     }
207
208     String error = "FAIL";
209
210     /**
211      * Sets the error that will be sent back to incoming "fast mail checks" that
212      * only check for the availability of a mailbox.
213      * 
214      * @param error
215      *            the error Massage to return in
216      *            {@link EmailProvider#checkEmailServer(int, String)}
217      */
218     public void setEmailCheckError(String error) {
219         this.error = error;
220     }
221
222     private Pattern approveRegex = Pattern.compile(".*");
223
224     /**
225      * Specifies a pattern that will be used for incoming
226      * {@link EmailProvider#checkEmailServer(int, String)} calls to determine
227      * whether the mailbox should exist.
228      * 
229      * @param approveRegex
230      *            the regex that will perform the check
231      */
232     public void setApproveRegex(Pattern approveRegex) {
233         this.approveRegex = approveRegex;
234     }
235
236     /**
237      * Removes all queued mails.
238      */
239     public void clearMails() {
240         mails.clear();
241     }
242
243     /**
244      * Resets this class to its initial state
245      * 
246      * @see #clearMails()
247      * @see #setApproveRegex(Pattern)
248      * @see #setEmailCheckError(String)
249      */
250     public void reset() {
251         clearMails();
252         error = "FAIL";
253         approveRegex = Pattern.compile(".*");
254     }
255
256     private boolean closed = false;
257
258     /**
259      * stops reading for incoming messages
260      * 
261      * @see #start()
262      */
263     public void destroy() {
264         try {
265             closed = true;
266             s.close();
267         } catch (IOException e) {
268             e.printStackTrace();
269         }
270     }
271
272     @Override
273     public String checkEmailServer(int forUid, String address) throws IOException {
274         return quickEmailCheck(address);
275     }
276
277     @Override
278     public void sendmail(String to, String subject, String message, String from, String replyto, String toname, String fromname, String errorsto, boolean extra) throws IOException {
279         mails.add(new TestMail(to, subject, message, from, replyto));
280     }
281
282 }