SmtpSenderUnitTests.java revision 2193962ca2b3157e79f731736afa2a0c972e778a
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;
21c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport com.android.email.provider.EmailContent.Attachment;
22c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport com.android.email.provider.EmailContent.Body;
23c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport com.android.email.provider.EmailContent.Message;
24c849936a36424645af73dc307b19778a89d6ee84Makoto Onukiimport com.android.email.provider.EmailProvider;
252193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.Address;
262193962ca2b3157e79f731736afa2a0c972e778aMarc Blankimport com.android.emailcommon.mail.MessagingException;
2796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
28c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport org.apache.commons.io.IOUtils;
29c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
30c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport android.content.Context;
31c849936a36424645af73dc307b19778a89d6ee84Makoto Onukiimport android.test.AndroidTestCase;
3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.test.suitebuilder.annotation.SmallTest;
3396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
34c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.ByteArrayInputStream;
35c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.File;
36c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.FileOutputStream;
37c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.IOException;
38c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.InputStream;
39c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.OutputStream;
40f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onukiimport java.net.InetAddress;
41f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onukiimport java.net.UnknownHostException;
42f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onukiimport java.util.regex.Pattern;
4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
4496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/**
4596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is a series of unit tests for the SMTP Sender class.  These tests must be locally
4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * complete - no server(s) required.
47c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler *
48c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * These tests can be run with the following command:
49c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler *   runtest -c com.android.email.mail.transport.SmtpSenderUnitTests email
5096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
5196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project@SmallTest
52c849936a36424645af73dc307b19778a89d6ee84Makoto Onukipublic class SmtpSenderUnitTests extends AndroidTestCase {
53c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
54c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    EmailProvider mProvider;
55c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    Context mProviderContext;
56c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    Context mContext;
57f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    private static final String LOCAL_ADDRESS = "1.2.3.4";
5896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
5996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /* These values are provided by setUp() */
6096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private SmtpSender mSender = null;
61c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
62c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /* Simple test string and its base64 equivalent */
63c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private final static String TEST_STRING = "Hello, world";
64c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private final static String TEST_STRING_BASE64 = "SGVsbG8sIHdvcmxk";
65c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
6696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Setup code.  We generate a lightweight SmtpSender for testing.
6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    protected void setUp() throws Exception {
7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        super.setUp();
72c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki        mProviderContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(
73c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki                getContext());
74c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mContext = getContext();
75c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // These are needed so we can get at the inner classes
77c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender = (SmtpSender) SmtpSender.newInstance(mProviderContext,
78c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler                "smtp://user:password@server:999");
7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Confirms simple non-SSL non-TLS login
8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
84f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    public void testSimpleLogin() throws Exception {
85c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = openAndInjectMockTransport();
87c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // try to open it
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        setupOpen(mockTransport, null);
9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mSender.open();
9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
92c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with SSL negotiation (faked)
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with SSL required but not supported
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with TLS negotiation (faked)
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with TLS required but not supported
9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test other capabilities.
9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test AUTH LOGIN
10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
101c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Test:  Open and send a single message (sunny day)
10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
105f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    public void testSendMessageWithBody() throws Exception {
10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = openAndInjectMockTransport();
107c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expectClose();
11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        setupOpen(mockTransport, null);
11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
112c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
113c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
114c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
115c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Body body = new Body();
116c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mMessageKey = message.mId;
117c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mTextContent = TEST_STRING;
118c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.save(mProviderContext);
119c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
120c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // prepare for the message traffic we'll see
121c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // TODO The test is a bit fragile, as we are order-dependent (and headers are not)
122c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
123c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: text/plain; charset=utf-8");
124c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
125c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
126c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(TEST_STRING_BASE64);
127c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
128c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
129c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
130c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
131c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
132c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
133c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
134c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with an empty attachment (no file) (sunny day)
135c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
136c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithEmptyAttachment() throws MessagingException, IOException {
137c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
138c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
139c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
140c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
141c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
142c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
143c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
144c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
145c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
146c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a bogus file (so we get headers only)
147c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, false);
148c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
149c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
150c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
151c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
152c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
153c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
154c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
155c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
156c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
157c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
158c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
159c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
160c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
161c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
162c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
163c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
164c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with an attachment (sunny day)
165c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
166c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithAttachment() throws MessagingException, IOException {
167c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
168c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
169c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
170c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
171c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
172c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
173c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
174c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
175c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
176c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a real file
177c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
178c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
179c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
180c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
181c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
182c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
183c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
184c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
185c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
186c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
187c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
188c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
189c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
190c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
191c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
192c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
193c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
194c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with two attachments
195c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
196c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithTwoAttachments() throws MessagingException, IOException {
197c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
198c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
199c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
200c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
201c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
202c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
203c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
204c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
205c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
206c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a real file
207c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
208c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
209c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
210c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a real file
211c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment2 = setupSimpleAttachment(mProviderContext, message.mId, true);
212c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment2.save(mProviderContext);
213c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
214c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
215c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
216c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
217c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
218c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
219c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
220c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
221c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment2);
222c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
223c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
224c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
225c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
226c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
227c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
228c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
229c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
230c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
231c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with body & attachment (sunny day)
232c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
233c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithBodyAndAttachment() throws MessagingException, IOException {
234c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
235c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
236c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
237c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
238c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
239c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
240c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
241c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
242c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
243c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Body body = new Body();
244c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mMessageKey = message.mId;
245c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mTextContent = TEST_STRING;
246c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.save(mProviderContext);
247c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
248c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
249c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
250c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
25196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // prepare for the message traffic we'll see
252c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
253c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
254c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
255c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
256c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: text/plain; charset=utf-8");
257c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
258c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
259c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(TEST_STRING_BASE64);
260c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
261c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
262c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
263c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
264c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
265c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
266c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
267c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
268c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
269c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
270c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
271c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to send a simple message (see setReceiveSimpleMessage)
272c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
273c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private Message setupSimpleMessage() {
274c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = new Message();
275c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mTimeStamp = System.currentTimeMillis();
276c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mFrom = Address.parseAndPack("Jones@Registry.Org");
277c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mTo = Address.parseAndPack("Smith@Registry.Org");
278c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mMessageId = "1234567890";
279c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        return message;
280c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
281c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
282c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
283c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to receive a simple message (see setupSimpleMessage)
284c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
285c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private void expectSimpleMessage(MockTransport mockTransport) {
286c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki        mockTransport.expect("MAIL FROM: <Jones@Registry.Org>",
28796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                "250 2.1.0 <Jones@Registry.Org> sender ok");
28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("RCPT TO: <Smith@Registry.Org>",
28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                "250 2.1.5 <Smith@Registry.Org> recipient ok");
29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("DATA", "354 enter mail, end with . on a line by itself");
291c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Date: .*");
292c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Message-ID: .*");
293c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("From: Jones@Registry.Org");
294c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("To: Smith@Registry.Org");
2956bcccf628413d40696980d0d86c7ab2b4f831952Andrew Stadler        mockTransport.expect("MIME-Version: 1.0");
296c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
29796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
298c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
299c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to send a simple attachment
300c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
301c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private Attachment setupSimpleAttachment(Context context, long messageId, boolean withBody)
302c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            throws IOException {
303c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = new Attachment();
304c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mFileName = "the file.jpg";
305c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mMimeType = "image/jpg";
306c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mSize = 0;
307c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mContentId = null;
308c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mContentUri = "content://com.android.email/1/1";
309c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mMessageKey = messageId;
310c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mLocation = null;
311c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mEncoding = null;
312c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
313c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        if (withBody) {
314c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            // Is there an easier way to set up a temp file?
315c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            InputStream inStream = new ByteArrayInputStream(TEST_STRING.getBytes());
316c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            File cacheDir = context.getCacheDir();
317c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            File tmpFile = File.createTempFile("setupSimpleAttachment", "tmp", cacheDir);
318c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            OutputStream outStream = new FileOutputStream(tmpFile);
319c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
320c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            IOUtils.copy(inStream, outStream);
321c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            attachment.mContentUri = "file://" + tmpFile.getAbsolutePath();
322c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        }
323c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
324c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        return attachment;
32596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
326c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
327c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
328c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to receive a simple attachment (note, no multipart support here)
329c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
330c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private void expectSimpleAttachment(MockTransport mockTransport, Attachment attachment) {
331c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: " + attachment.mMimeType + ";");
332c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" name=\"" + attachment.mFileName + "\"");
333c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
334c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Disposition: attachment;");
335c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" filename=\"" + attachment.mFileName + "\";");
336c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" size=" + Long.toString(attachment.mSize));
337c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
338c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        if (attachment.mContentUri != null && attachment.mContentUri.startsWith("file://")) {
339c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            mockTransport.expect(TEST_STRING_BASE64);
340c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        }
341c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
342c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
34396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
344b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler     * Test:  Recover from a server closing early (or returning an empty string)
345b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler     */
346f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    public void testEmptyLineResponse() throws Exception {
347b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
348c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
349b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
350b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        mockTransport.expectClose();
351c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
352b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Load up just the bare minimum to expose the error
353b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        mockTransport.expect(null, "220 MockTransport 2000 Ready To Assist You Peewee");
354f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki        mockTransport.expect("EHLO " + Pattern.quote(LOCAL_ADDRESS), "");
355c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
356b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Now trigger the transmission
357b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Note, a null message is sufficient here, as we won't even get past open()
358b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        try {
359c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            mSender.sendMessage(-1);
360b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            fail("Should not be able to send with failed open()");
361b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        } catch (MessagingException me) {
362b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            // good - expected
363b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            // TODO maybe expect a particular exception?
364b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        }
365b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler    }
366c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
367b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler    /**
36896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Set up a basic MockTransport. open it, and inject it into mStore
36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
370f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki    private MockTransport openAndInjectMockTransport() throws UnknownHostException {
37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Create mock transport and inject it into the SmtpSender that's already set up
37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = new MockTransport();
373e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler        mockTransport.setSecurity(Transport.CONNECTION_SECURITY_NONE, false);
37496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mSender.setTransport(mockTransport);
375f4dac9f266906a84f4710d8af5d4a24f2290b1baMakoto Onuki        mockTransport.setMockLocalAddress(InetAddress.getByName(LOCAL_ADDRESS));
37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mockTransport;
37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
378c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki
37996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
38096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Helper which stuffs the mock with enough strings to satisfy a call to SmtpSender.open()
381c849936a36424645af73dc307b19778a89d6ee84Makoto Onuki     *
38296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param mockTransport the mock transport we're using
38396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param capabilities if non-null, comma-separated list of capabilities
38496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
38596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private void setupOpen(MockTransport mockTransport, String capabilities) {
38696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect(null, "220 MockTransport 2000 Ready To Assist You Peewee");
38796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("EHLO .*", "250-10.20.30.40 hello");
38896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (capabilities == null) {
38996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-HELP");
39096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-AUTH LOGIN PLAIN CRAM-MD5");
39196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-SIZE 15728640");
39296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-ENHANCEDSTATUSCODES");
39396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            mockTransport.expect(null, "250-8BITMIME");
39496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        } else {
39596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            for (String capability : capabilities.split(",")) {
39696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                mockTransport.expect(null, "250-" + capability);
39796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            }
39896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
39996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect(null, "250+OK");
40096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("AUTH PLAIN .*", "235 2.7.0 ... authentication succeeded");
40196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
40296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project}
403