1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tradefed.util; 18 19 import com.android.tradefed.util.IEmail.Message; 20 21 import junit.framework.TestCase; 22 23 import java.io.ByteArrayOutputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.io.OutputStream; 27 import java.util.HashMap; 28 import java.util.Map; 29 30 public class EmailTest extends TestCase { 31 private TestEmail mEmail = null; 32 33 /** 34 * A mock class to let us capture the data that is passed to the process on stdin 35 */ 36 class TestProcess extends Process { 37 OutputStream mOutputStream = null; 38 39 TestProcess(OutputStream stream) { 40 mOutputStream = stream; 41 } 42 43 @Override 44 public OutputStream getOutputStream() { 45 return mOutputStream; 46 } 47 48 // Add stubs for all the abstract methods 49 class StubInputStream extends InputStream { 50 @Override 51 public int read() {return 0;} 52 } 53 54 @Override 55 public void destroy() {} 56 @Override 57 public int exitValue() {return 0;} 58 @Override 59 public int waitFor() {return 0;} 60 @Override 61 public InputStream getInputStream() { 62 return new StubInputStream(); 63 } 64 @Override 65 public InputStream getErrorStream() { 66 return new StubInputStream(); 67 } 68 } 69 70 /** 71 * A mock class that doesn't actually run anything, but instead returns a mock Process to 72 * capture the data that would be passed _to_ the process on stdin. Java's naming of these 73 * methods is insane. 74 */ 75 class TestEmail extends Email { 76 ByteArrayOutputStream mOutputStream = null; 77 78 TestEmail() { 79 mOutputStream = new ByteArrayOutputStream(); 80 } 81 82 public String getMailerData() { 83 return mOutputStream.toString(); 84 } 85 86 @Override 87 Process run(String[] cmd) { 88 return new TestProcess(mOutputStream); 89 } 90 } 91 92 @Override 93 public void setUp() throws Exception { 94 super.setUp(); 95 96 mEmail = new TestEmail(); 97 } 98 99 /** 100 * Ensure that IllegalArgumentException is thrown when a message without a destination address 101 * is sent. Note that the address is not validated in any way (it could even be null) 102 */ 103 public void testSendInval_destination() throws IOException { 104 Message msg = new Message(); 105 msg.setSubject("subject"); 106 msg.setBody("body"); 107 108 try { 109 mEmail.send(msg); 110 fail("IllegalArgumentException not thrown"); 111 } catch (IllegalArgumentException e) { 112 // expected 113 } 114 } 115 116 /** 117 * Ensure that IllegalArgumentException is thrown when a message without a subject is sent. 118 */ 119 public void testSendInval_subject() throws IOException { 120 Message msg = new Message("dest (at) ination.com", null, "body"); 121 try { 122 mEmail.send(msg); 123 fail("IllegalArgumentException not thrown"); 124 } catch (IllegalArgumentException e) { 125 // expected 126 } 127 } 128 129 /** 130 * Ensure that IllegalArgumentException is thrown when a message without a body is sent. 131 */ 132 public void testSendInval_body() throws IOException { 133 Message msg = new Message("dest (at) ination.com", "subject", null); 134 try { 135 mEmail.send(msg); 136 fail("IllegalArgumentException not thrown"); 137 } catch (IllegalArgumentException e) { 138 // expected 139 } 140 } 141 142 /** 143 * Ensure that the email body is passed correctly to the mailer program's standard input 144 */ 145 public void testSend_simple() throws IOException { 146 final Message msg = new Message("dest (at) ination.com", "subject", "body"); 147 msg.setSender("or (at) igin.com"); 148 mEmail.send(msg); 149 150 final Map<String, String> headers = new HashMap<String, String>(); 151 final String body = extractBody(mEmail.getMailerData(), headers); 152 153 assertEquals("body", body); 154 assertEquals("or (at) igin.com", headers.get("From")); 155 assertEquals("dest (at) ination.com", headers.get("To")); 156 assertEquals("subject", headers.get("Subject")); 157 assertEquals(Message.PLAIN, headers.get("Content-type")); 158 assertEquals(4, headers.size()); 159 } 160 161 /** 162 * Make sure that the HTML flag is passed along correctly 163 */ 164 public void testSend_htmlEmail() throws IOException { 165 final String expectedBody = "<html><body>le body</body></html>"; 166 final Message msg = new Message("dest (at) ination.com", "subject", expectedBody); 167 msg.setHtml(true); 168 mEmail.send(msg); 169 170 final Map<String, String> headers = new HashMap<String, String>(); 171 final String body = extractBody(mEmail.getMailerData(), headers); 172 173 assertEquals(expectedBody, body); 174 assertEquals(Message.HTML, headers.get("Content-type")); 175 } 176 177 /** 178 * Ensure that the email is sent correctly even if the message has an empty (but present) 179 * subject 180 */ 181 public void testSend_emptySubject() throws IOException { 182 Message msg = new Message("dest (at) ination.com", "", "body"); 183 mEmail.send(msg); 184 assertTrue("body".equals(extractBody(mEmail.getMailerData()))); 185 } 186 187 /** 188 * Ensure that the email is sent correctly even if the message has an empty (but present) body. 189 */ 190 public void testSend_emptyBody() throws IOException { 191 Message msg = new Message("dest (at) ination.com", "subject", ""); 192 mEmail.send(msg); 193 assertTrue("".equals(extractBody(mEmail.getMailerData()))); 194 } 195 196 /** 197 * A short functional test to send an email somewhere. Intended to be manually enabled with 198 * appropriate email addresses to verify that Email functionality is working after changes. 199 * Not enabled by default because the particular addresses to use will depend on the environment 200 */ 201 @SuppressWarnings("unused") 202 public void _manual_testFuncSend() throws IOException { 203 final String sender = null; 204 final String[] to = {"RECIPIENT"}; 205 final String[] cc = {}; 206 final String[] bcc = {}; 207 208 final String subject = "This is a TF test email"; 209 final String body = "<html><body><h1>What do we want?!</h1><h2>Time travel!</h2>" + 210 "When do we want it?<span style=\"display:block;color:blue;font-weight:bold\">" + 211 "it's irrelevant!</span></body></html>"; 212 final String contentType = Message.HTML; 213 214 final Message msg = new Message(); 215 msg.setSubject(subject); 216 msg.setBody(body); 217 msg.setContentType(contentType); 218 if (sender != null) { 219 msg.setSender(sender); 220 } 221 for (String addr : to) { 222 msg.addTo(addr); 223 } 224 for (String addr : cc) { 225 msg.addCc(addr); 226 } 227 for (String addr : bcc) { 228 msg.addBcc(addr); 229 } 230 231 final IEmail mailer = new Email(); 232 mailer.send(msg); 233 } 234 235 private String extractBody(String data) { 236 return extractBody(data, null); 237 } 238 239 /** 240 * Helper function that takes a full email and splits it into the headers and the body. 241 * Optionally returns the headers via the second arg 242 */ 243 private String extractBody(String data, Map<String, String> headers) { 244 final String[] pieces = data.split(Email.CRLF + Email.CRLF, 2); 245 if (headers != null) { 246 for (String header : pieces[0].split(Email.CRLF)) { 247 final String[] halves = header.split(": ", 2); 248 final String key = halves[0]; 249 final String val = halves.length == 2 ? halves[1] : null; 250 251 headers.put(key, val); 252 } 253 } 254 255 if (pieces.length < 2) { 256 return null; 257 } else { 258 return pieces[1]; 259 } 260 } 261 } 262 263