SmtpSenderUnitTests.java revision daf869cf60de75bc91ed3aef6ac0bff1fe371733
196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/*
296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * you may not use this file except in compliance with the License.
696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * You may obtain a copy of the License at
796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * See the License for the specific language governing permissions and
1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * limitations under the License.
1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.android.email.mail.transport;
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
19c849936a36424645af73dc307b19778a89d6ee84Makoto Onukiimport com.android.email.DBTestHelper;
2096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.Transport;
21c849936a36424645af73dc307b19778a89d6ee84Makoto Onukiimport com.android.email.provider.EmailProvider;
222193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Address;
232193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessagingException;
24daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedyimport com.android.emailcommon.provider.EmailContent.Account;
25a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Attachment;
26a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Body;
27daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedyimport com.android.emailcommon.provider.EmailContent.HostAuth;
28a7bc0319a75184ad706bb35c049af107ac3688e6Marc Blankimport com.android.emailcommon.provider.EmailContent.Message;
2996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
30c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport org.apache.commons.io.IOUtils;
31c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
32c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport android.content.Context;
33c849936a36424645af73dc307b19778a89d6ee84Makoto Onukiimport android.test.AndroidTestCase;
3496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.test.suitebuilder.annotation.SmallTest;
3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
36c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.ByteArrayInputStream;
37c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.File;
38c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.FileOutputStream;
39c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.IOException;
40c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.InputStream;
41c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.OutputStream;
42f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onukiimport java.net.InetAddress;
43f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onukiimport java.net.UnknownHostException;
44f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onukiimport java.util.regex.Pattern;
4596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/**
4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is a series of unit tests for the SMTP Sender class.  These tests must be locally
4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * complete - no server(s) required.
49c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler *
50c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * These tests can be run with the following command:
51c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler *   runtest -c com.android.email.mail.transport.SmtpSenderUnitTests email
5296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project@SmallTest
54c849936a36424645af73dc307b19778a89d6ee84Makoto Onukipublic class SmtpSenderUnitTests extends AndroidTestCase {
55c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
56c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    EmailProvider mProvider;
57c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    Context mProviderContext;
58c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    Context mContext;
59f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    private static final String LOCAL_ADDRESS = "1.2.3.4";
6096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
6196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /* These values are provided by setUp() */
6296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private SmtpSender mSender = null;
63c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
64c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /* Simple test string and its base64 equivalent */
65c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private final static String TEST_STRING = "Hello, world";
66c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private final static String TEST_STRING_BASE64 = "SGVsbG8sIHdvcmxk";
67c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Setup code.  We generate a lightweight SmtpSender for testing.
7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    protected void setUp() throws Exception {
7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        super.setUp();
74c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki        mProviderContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(
75c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki                getContext());
76c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mContext = getContext();
77c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
78daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedy        HostAuth testAuth = new HostAuth();
79daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedy        Account testAccount = new Account();
80daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedy
81daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedy        testAuth.setLogin("user", "password");
82daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedy        testAuth.setConnection("smtp", "server", 999);
83daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedy        testAccount.mHostAuthSend = testAuth;
84daf869cf60de75bc91ed3aef6ac0bff1fe371733Todd Kennedy        mSender = (SmtpSender) SmtpSender.newInstance(testAccount, mProviderContext);
8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Confirms simple non-SSL non-TLS login
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
90f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    public void testSimpleLogin() throws Exception {
91c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = openAndInjectMockTransport();
93c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // try to open it
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        setupOpen(mockTransport, null);
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mSender.open();
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
98c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with SSL negotiation (faked)
10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with SSL required but not supported
10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with TLS negotiation (faked)
10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with TLS required but not supported
10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test other capabilities.
10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test AUTH LOGIN
10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
107c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Test:  Open and send a single message (sunny day)
11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
111f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    public void testSendMessageWithBody() throws Exception {
11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = openAndInjectMockTransport();
113c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expectClose();
11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        setupOpen(mockTransport, null);
11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
118c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
119c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
120c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
121c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Body body = new Body();
122c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mMessageKey = message.mId;
123c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mTextContent = TEST_STRING;
124c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.save(mProviderContext);
125c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
126c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // prepare for the message traffic we'll see
127c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // TODO The test is a bit fragile, as we are order-dependent (and headers are not)
128c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
129c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: text/plain; charset=utf-8");
130c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
131c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
132c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(TEST_STRING_BASE64);
133c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
134c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
135c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
136c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
137c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
138c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
139c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
140c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with an empty attachment (no file) (sunny day)
141c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
142c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithEmptyAttachment() throws MessagingException, IOException {
143c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
144c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
145c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
146c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
147c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
148c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
149c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
150c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
151c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
152c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a bogus file (so we get headers only)
153c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, false);
154c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
155c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
156c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
157c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
158c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
159c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
160c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
161c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
162c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
163c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
164c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
165c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
166c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
167c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
168c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
169c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
170c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with an attachment (sunny day)
171c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
172c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithAttachment() throws MessagingException, IOException {
173c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
174c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
175c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
176c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
177c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
178c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
179c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
180c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
181c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
182c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a real file
183c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
184c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
185c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
186c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
187c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
188c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
189c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
190c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
191c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
192c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
193c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
194c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
195c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
196c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
197c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
198c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
199c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
200c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with two attachments
201c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
202c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithTwoAttachments() throws MessagingException, IOException {
203c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
204c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
205c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
206c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
207c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
208c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
209c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
210c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
211c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
212c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a real file
213c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
214c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
215c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
216c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a real file
217c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment2 = setupSimpleAttachment(mProviderContext, message.mId, true);
218c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment2.save(mProviderContext);
219c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
220c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
221c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
222c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
223c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
224c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
225c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
226c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
227c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment2);
228c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
229c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
230c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
231c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
232c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
233c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
234c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
235c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
236c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
237c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with body & attachment (sunny day)
238c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
239c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithBodyAndAttachment() throws MessagingException, IOException {
240c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
241c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
242c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
243c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
244c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
245c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
246c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
247c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
248c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
249c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Body body = new Body();
250c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mMessageKey = message.mId;
251c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mTextContent = TEST_STRING;
252c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.save(mProviderContext);
253c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
254c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
255c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
256c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
25796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // prepare for the message traffic we'll see
258c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
259c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
260c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
261c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
262c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: text/plain; charset=utf-8");
263c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
264c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
265c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(TEST_STRING_BASE64);
266c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
267c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
268c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
269c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
270c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
271c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
272c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
273c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
274c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
275c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
276c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
277c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to send a simple message (see setReceiveSimpleMessage)
278c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
279c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private Message setupSimpleMessage() {
280c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = new Message();
281c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mTimeStamp = System.currentTimeMillis();
282c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mFrom = Address.parseAndPack("Jones@Registry.Org");
283c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mTo = Address.parseAndPack("Smith@Registry.Org");
284c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mMessageId = "1234567890";
285c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        return message;
286c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
287c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
288c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
289c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to receive a simple message (see setupSimpleMessage)
290c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
291c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private void expectSimpleMessage(MockTransport mockTransport) {
292c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki        mockTransport.expect("MAIL FROM: <Jones@Registry.Org>",
29396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                "250 2.1.0 <Jones@Registry.Org> sender ok");
29496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("RCPT TO: <Smith@Registry.Org>",
29596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                "250 2.1.5 <Smith@Registry.Org> recipient ok");
29696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("DATA", "354 enter mail, end with . on a line by itself");
297c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Date: .*");
298c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Message-ID: .*");
299c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("From: Jones@Registry.Org");
300c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("To: Smith@Registry.Org");
3016bcccf628413d40696980d0d86c7ab2b4f831952Andrew Stadler        mockTransport.expect("MIME-Version: 1.0");
302c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
30396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
304c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
305c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to send a simple attachment
306c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
307c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private Attachment setupSimpleAttachment(Context context, long messageId, boolean withBody)
308c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            throws IOException {
309c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = new Attachment();
310c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mFileName = "the file.jpg";
311c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mMimeType = "image/jpg";
312c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mSize = 0;
313c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mContentId = null;
314c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mContentUri = "content://com.android.email/1/1";
315c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mMessageKey = messageId;
316c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mLocation = null;
317c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mEncoding = null;
318c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
319c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        if (withBody) {
320c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            // Is there an easier way to set up a temp file?
321c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            InputStream inStream = new ByteArrayInputStream(TEST_STRING.getBytes());
322c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            File cacheDir = context.getCacheDir();
323c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            File tmpFile = File.createTempFile("setupSimpleAttachment", "tmp", cacheDir);
324c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            OutputStream outStream = new FileOutputStream(tmpFile);
325c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
326c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            IOUtils.copy(inStream, outStream);
327c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            attachment.mContentUri = "file://" + tmpFile.getAbsolutePath();
328c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        }
329c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
330c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        return attachment;
33196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
332c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
333c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
334c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to receive a simple attachment (note, no multipart support here)
335c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
336c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private void expectSimpleAttachment(MockTransport mockTransport, Attachment attachment) {
337c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: " + attachment.mMimeType + ";");
338c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" name=\"" + attachment.mFileName + "\"");
339c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
340c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Disposition: attachment;");
341c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" filename=\"" + attachment.mFileName + "\";");
342c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" size=" + Long.toString(attachment.mSize));
343c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
344c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        if (attachment.mContentUri != null && attachment.mContentUri.startsWith("file://")) {
345c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            mockTransport.expect(TEST_STRING_BASE64);
346c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        }
347c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
348c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
34996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
350b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler     * Test:  Recover from a server closing early (or returning an empty string)
351b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler     */
352f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    public void testEmptyLineResponse() throws Exception {
353b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
354c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
355b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
356b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        mockTransport.expectClose();
357c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
358b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Load up just the bare minimum to expose the error
359b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        mockTransport.expect(null, "220 MockTransport 2000 Ready To Assist You Peewee");
360f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki        mockTransport.expect("EHLO " + Pattern.quote(LOCAL_ADDRESS), "");
361c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
362b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Now trigger the transmission
363b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Note, a null message is sufficient here, as we won't even get past open()
364b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        try {
365c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            mSender.sendMessage(-1);
366b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            fail("Should not be able to send with failed open()");
367b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        } catch (MessagingException me) {
368b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            // good - expected
369b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            // TODO maybe expect a particular exception?
370b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        }
371b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler    }
372c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
373b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler    /**
37496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Set up a basic MockTransport. open it, and inject it into mStore
37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
376f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    private MockTransport openAndInjectMockTransport() throws UnknownHostException {
37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Create mock transport and inject it into the SmtpSender that's already set up
37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = new MockTransport();
379e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler        mockTransport.setSecurity(Transport.CONNECTION_SECURITY_NONE, false);
38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mSender.setTransport(mockTransport);
381f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki        mockTransport.setMockLocalAddress(InetAddress.getByName(LOCAL_ADDRESS));
38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mockTransport;
38396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
384c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Helper which stuffs the mock with enough strings to satisfy a call to SmtpSender.open()
387c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki     *
38896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param mockTransport the mock transport we're using
38996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param capabilities if non-null, comma-separated list of capabilities
39096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
39196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private void setupOpen(MockTransport mockTransport, String capabilities) {
39296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect(null, "220 MockTransport 2000 Ready To Assist You Peewee");
39396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("EHLO .*", "250-10.20.30.40 hello");
39496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (capabilities == null) {
39596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-HELP");
39696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-AUTH LOGIN PLAIN CRAM-MD5");
39796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-SIZE 15728640");
39896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-ENHANCEDSTATUSCODES");
39996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-8BITMIME");
40096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
40196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            for (String capability : capabilities.split(",")) {
40296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                mockTransport.expect(null, "250-" + capability);
40396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
40496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
40596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect(null, "250+OK");
40696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("AUTH PLAIN .*", "235 2.7.0 ... authentication succeeded");
40796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
40896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project}
409