]> WPIA git - gigi.git/blob - tests/club/wpia/gigi/testUtils/TestEmailReceiver.java
Merge "add: show more certificates on the "roots" page"
[gigi.git] / tests / club / wpia / gigi / testUtils / TestEmailReceiver.java
1 package club.wpia.gigi.testUtils;
2
3 import static org.junit.Assert.*;
4
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;
10 import java.net.URL;
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;
16
17 import club.wpia.gigi.email.EmailProvider;
18 import club.wpia.gigi.email.TestEmailProvider;
19
20 /**
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.
25  */
26 public final class TestEmailReceiver extends EmailProvider implements Runnable, MailReceiver {
27
28     /**
29      * An email that has been intercepted.
30      */
31     public static class TestMail {
32
33         String to;
34
35         String subject;
36
37         String message;
38
39         String replyto;
40
41         public TestMail(String to, String subject, String message, String replyto) {
42             this.to = to;
43             this.subject = subject;
44             this.message = message;
45             this.replyto = replyto;
46         }
47
48         public String getTo() {
49             return to;
50         }
51
52         public String getSubject() {
53             return subject;
54         }
55
56         public String getMessage() {
57             return message;
58         }
59
60         public String getReplyto() {
61             return replyto;
62         }
63
64         public String extractLink() {
65             Pattern link = Pattern.compile("https?://[^\\s]+(?=\\s)");
66             Matcher m = link.matcher(getMessage());
67             m.find();
68             return m.group(0);
69         }
70
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]);
75
76             URLConnection csrfConn = u.openConnection();
77             String csrf = ManagedTest.getCSRF(csrfConn, 0);
78
79             u = new URL("https://" + ManagedTest.getServerName() + "/verify");
80             URLConnection uc = u.openConnection();
81             ManagedTest.cookie(uc, ManagedTest.stripCookie(csrfConn.getHeaderField("Set-Cookie")));
82             uc.setDoOutput(true);
83             uc.getOutputStream().write((parts[1] + "&csrf=" + csrf).getBytes("UTF-8"));
84             uc.connect();
85             uc.getInputStream().close();
86         }
87
88         @Override
89         public String toString() {
90             return "TestMail: " + subject + " for " + to;
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 receiver").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     @Override
139     public TestMail receive(String to) {
140         TestMail poll;
141
142         try {
143             poll = mails.poll(60, TimeUnit.SECONDS);
144
145         } catch (InterruptedException e) {
146             throw new AssertionError("Interrupted while receiving mails");
147         }
148         if (poll == null) {
149             throw new AssertionError("Mail receiving timed out");
150         }
151         if (to != null) {
152             assertEquals(to, poll.getTo());
153         }
154
155         return poll;
156     }
157
158     /**
159      * Retrieves an outgoing mail from the system or returns <code>null</code>
160      * if there was no mail sent in 30 seconds.
161      * 
162      * @return The intercepted {@link TestMail} or <code>null</code> if no mail
163      *         has been sent.
164      * @see #receive()
165      */
166     public TestMail poll(String to) {
167         TestMail tm = mails.poll();
168         if (tm != null && to != null) {
169             assertEquals(to, tm.getTo());
170         }
171         return tm;
172     }
173
174     @Override
175     public void run() {
176         try {
177             while (true) {
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));
188                     dos.flush();
189                 } else if (type.equals("ping")) {
190                 } else {
191                     System.err.println("Unknown type: " + type);
192                 }
193             }
194         } catch (IOException e) {
195             if ( !closed) {
196                 e.printStackTrace();
197             }
198         }
199
200     }
201
202     private String quickEmailCheck(String email) throws IOException {
203         if (approveRegex.matcher(email).matches()) {
204             return "OK";
205         } else {
206             return error;
207         }
208     }
209
210     String error = "FAIL";
211
212     /**
213      * Sets the error that will be sent back to incoming "fast mail checks" that
214      * only check for the availability of a mailbox.
215      * 
216      * @param error
217      *            the error Massage to return in
218      *            {@link EmailProvider#checkEmailServer(int, String)}
219      */
220     public void setEmailCheckError(String error) {
221         this.error = error;
222     }
223
224     private Pattern approveRegex = Pattern.compile(".*");
225
226     /**
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.
230      * 
231      * @param approveRegex
232      *            the regex that will perform the check
233      */
234     public void setApproveRegex(Pattern approveRegex) {
235         this.approveRegex = approveRegex;
236     }
237
238     /**
239      * Removes all queued mails.
240      */
241     @Override
242     public void assertEmpty() {
243         int originalSize = mails.size();
244         mails.clear();
245         assertEquals("test case should consume all produced emails", 0, originalSize);
246     }
247
248     /**
249      * Resets this class to its initial state
250      * 
251      * @see #assertEmpty()
252      * @see #setApproveRegex(Pattern)
253      * @see #setEmailCheckError(String)
254      */
255     public void reset() {
256         assertEmpty();
257         error = "FAIL";
258         approveRegex = Pattern.compile(".*");
259     }
260
261     private boolean closed = false;
262
263     /**
264      * stops reading for incoming messages
265      * 
266      * @see #start()
267      */
268     public void destroy() {
269         try {
270             closed = true;
271             s.close();
272         } catch (IOException e) {
273             e.printStackTrace();
274         }
275     }
276
277     @Override
278     public String checkEmailServer(int forUid, String address) throws IOException {
279         return quickEmailCheck(address);
280     }
281
282     @Override
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));
285     }
286
287 }