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