SmtpSenderUnitTests.java revision e4a7cc440f081ef9c4375a2bd2f82680cc11b152
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
1996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.Address;
2096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.MessagingException;
2196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport com.android.email.mail.Transport;
22c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport com.android.email.provider.EmailProvider;
23c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport com.android.email.provider.EmailContent.Attachment;
24c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport com.android.email.provider.EmailContent.Body;
25c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport com.android.email.provider.EmailContent.Message;
2696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
27c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport org.apache.commons.io.IOUtils;
28c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
29c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport android.content.Context;
30c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport android.test.ProviderTestCase2;
3196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport android.test.suitebuilder.annotation.SmallTest;
3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
33c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.ByteArrayInputStream;
34c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.File;
35c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.FileOutputStream;
36c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.IOException;
37c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.InputStream;
38c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerimport java.io.OutputStream;
3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/**
4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * This is a series of unit tests for the SMTP Sender class.  These tests must be locally
4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * complete - no server(s) required.
43c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler *
44c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler * These tests can be run with the following command:
45c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler *   runtest -c com.android.email.mail.transport.SmtpSenderUnitTests email
4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project@SmallTest
48c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadlerpublic class SmtpSenderUnitTests extends ProviderTestCase2<EmailProvider> {
49c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
50c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    EmailProvider mProvider;
51c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    Context mProviderContext;
52c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    Context mContext;
5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
5496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /* These values are provided by setUp() */
5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private SmtpSender mSender = null;
56c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
57c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /* Simple test string and its base64 equivalent */
58c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private final static String TEST_STRING = "Hello, world";
59c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private final static String TEST_STRING_BASE64 = "SGVsbG8sIHdvcmxk";
60c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
61c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public SmtpSenderUnitTests() {
62c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
63c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
64c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
6696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Setup code.  We generate a lightweight SmtpSender for testing.
6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    @Override
6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    protected void setUp() throws Exception {
7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        super.setUp();
71c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mProviderContext = getMockContext();
72c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mContext = getContext();
7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // These are needed so we can get at the inner classes
75c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender = (SmtpSender) SmtpSender.newInstance(mProviderContext,
76c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler                "smtp://user:password@server:999");
7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Confirms simple non-SSL non-TLS login
8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    public void testSimpleLogin() throws MessagingException {
8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = openAndInjectMockTransport();
8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // try to open it
8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        setupOpen(mockTransport, null);
8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mSender.open();
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with SSL negotiation (faked)
9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with SSL required but not supported
9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with TLS negotiation (faked)
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test with TLS required but not supported
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test other capabilities.
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * TODO: Test AUTH LOGIN
9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Test:  Open and send a single message (sunny day)
10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
103c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithBody() throws MessagingException {
10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = openAndInjectMockTransport();
105c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expectClose();
10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        setupOpen(mockTransport, null);
10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
110c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
111c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
112c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
113c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Body body = new Body();
114c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mMessageKey = message.mId;
115c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mTextContent = TEST_STRING;
116c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.save(mProviderContext);
117c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
118c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // prepare for the message traffic we'll see
119c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // TODO The test is a bit fragile, as we are order-dependent (and headers are not)
120c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
121c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: text/plain; charset=utf-8");
122c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
123c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
124c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(TEST_STRING_BASE64);
125c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
126c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
127c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
128c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
129c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
130c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
131c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
132c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with an empty attachment (no file) (sunny day)
133c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
134c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithEmptyAttachment() throws MessagingException, IOException {
135c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
136c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
137c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
138c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
139c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
140c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
141c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
142c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
143c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
144c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a bogus file (so we get headers only)
145c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, false);
146c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
147c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
148c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
149c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("MIME-Version: 1.0");
150c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
151c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
152c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
153c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
154c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
155c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
156c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
157c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
158c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
159c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
160c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
161c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
162c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
163c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with an attachment (sunny day)
164c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
165c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithAttachment() throws MessagingException, IOException {
166c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
167c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
168c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
169c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
170c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
171c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
172c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
173c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
174c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
175c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Creates an attachment with a real file
176c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
177c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
178c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
179c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
180c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("MIME-Version: 1.0");
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("MIME-Version: 1.0");
216c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
217c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
218c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
219c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
220c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
221c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
222c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment2);
223c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
224c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
225c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
226c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
227c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
228c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
229c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
230c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
231c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
232c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Test:  Open and send a single message with body & attachment (sunny day)
233c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
234c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testSendMessageWithBodyAndAttachment() throws MessagingException, IOException {
235c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
236c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
237c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
238c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expectClose();
239c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        setupOpen(mockTransport, null);
240c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
241c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = setupSimpleMessage();
242c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.save(mProviderContext);
243c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
244c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Body body = new Body();
245c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mMessageKey = message.mId;
246c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.mTextContent = TEST_STRING;
247c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        body.save(mProviderContext);
248c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
249c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = setupSimpleAttachment(mProviderContext, message.mId, true);
250c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.save(mProviderContext);
251c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
25296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // prepare for the message traffic we'll see
253c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleMessage(mockTransport);
254c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("MIME-Version: 1.0");
255c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: multipart/mixed; boundary=\".*");
256c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
257c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
258c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: text/plain; charset=utf-8");
259c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
260c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
261c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(TEST_STRING_BASE64);
262c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*");
263c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        expectSimpleAttachment(mockTransport, attachment);
264c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
265c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("----.*--");
266c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("\r\n\\.", "250 2.0.0 kv2f1a00C02Rf8w3Vv mail accepted for delivery");
267c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
268c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        // Now trigger the transmission
269c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mSender.sendMessage(message.mId);
270c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
271c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
272c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
273c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to send a simple message (see setReceiveSimpleMessage)
274c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
275c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private Message setupSimpleMessage() {
276c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Message message = new Message();
277c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mTimeStamp = System.currentTimeMillis();
278c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mFrom = Address.parseAndPack("Jones@Registry.Org");
279c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mTo = Address.parseAndPack("Smith@Registry.Org");
280c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        message.mMessageId = "1234567890";
281c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        return message;
282c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
283c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
284c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
285c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to receive a simple message (see setupSimpleMessage)
286c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
287c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private void expectSimpleMessage(MockTransport mockTransport) {
28896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("MAIL FROM: <Jones@Registry.Org>",
28996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                "250 2.1.0 <Jones@Registry.Org> sender ok");
29096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("RCPT TO: <Smith@Registry.Org>",
29196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                "250 2.1.5 <Smith@Registry.Org> recipient ok");
29296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mockTransport.expect("DATA", "354 enter mail, end with . on a line by itself");
293c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Date: .*");
294c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Message-ID: .*");
295c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("From: Jones@Registry.Org");
296c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("To: Smith@Registry.Org");
297c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
29896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
299c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
300c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to send a simple attachment
301c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
302c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private Attachment setupSimpleAttachment(Context context, long messageId, boolean withBody)
303c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            throws IOException {
304c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        Attachment attachment = new Attachment();
305c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mFileName = "the file.jpg";
306c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mMimeType = "image/jpg";
307c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mSize = 0;
308c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mContentId = null;
309c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mContentUri = "content://com.android.email/1/1";
310c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mMessageKey = messageId;
311c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mLocation = null;
312c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        attachment.mEncoding = null;
313c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
314c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        if (withBody) {
315c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            // Is there an easier way to set up a temp file?
316c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            InputStream inStream = new ByteArrayInputStream(TEST_STRING.getBytes());
317c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            File cacheDir = context.getCacheDir();
318c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            File tmpFile = File.createTempFile("setupSimpleAttachment", "tmp", cacheDir);
319c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            OutputStream outStream = new FileOutputStream(tmpFile);
320c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
321c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            IOUtils.copy(inStream, outStream);
322c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            attachment.mContentUri = "file://" + tmpFile.getAbsolutePath();
323c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        }
324c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
325c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        return attachment;
32696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
327c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
328c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    /**
329c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     * Prepare to receive a simple attachment (note, no multipart support here)
330c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler     */
331c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    private void expectSimpleAttachment(MockTransport mockTransport, Attachment attachment) {
332c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Type: " + attachment.mMimeType + ";");
333c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" name=\"" + attachment.mFileName + "\"");
334c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Transfer-Encoding: base64");
335c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("Content-Disposition: attachment;");
336c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" filename=\"" + attachment.mFileName + "\";");
337c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect(" size=" + Long.toString(attachment.mSize));
338c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        mockTransport.expect("");
339c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        if (attachment.mContentUri != null && attachment.mContentUri.startsWith("file://")) {
340c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            mockTransport.expect(TEST_STRING_BASE64);
341c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler        }
342c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    }
343c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler
34496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
345b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler     * Test:  Recover from a server closing early (or returning an empty string)
346b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler     */
347c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler    public void testEmptyLineResponse() {
348b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        MockTransport mockTransport = openAndInjectMockTransport();
349b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler
350b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Since SmtpSender.sendMessage() does a close then open, we need to preset for the open
351b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        mockTransport.expectClose();
352b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler
353b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Load up just the bare minimum to expose the error
354b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        mockTransport.expect(null, "220 MockTransport 2000 Ready To Assist You Peewee");
355b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        mockTransport.expect("EHLO .*", "");
356b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler
357b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Now trigger the transmission
358b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        // Note, a null message is sufficient here, as we won't even get past open()
359b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        try {
360c640cbbaf385566e1b6de361b2b23156e10f695dAndrew Stadler            mSender.sendMessage(-1);
361b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            fail("Should not be able to send with failed open()");
362b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        } catch (MessagingException me) {
363b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            // good - expected
364b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler            // TODO maybe expect a particular exception?
365b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler        }
366b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler    }
367b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler
368b011a812e05902d7e417b8c47acc90a592f4b412Andrew Stadler    /**
36996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Set up a basic MockTransport. open it, and inject it into mStore
37096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
37196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private MockTransport openAndInjectMockTransport() {
37296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        // Create mock transport and inject it into the SmtpSender that's already set up
37396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        MockTransport mockTransport = new MockTransport();
374e4a7cc440f081ef9c4375a2bd2f82680cc11b152Andrew Stadler        mockTransport.setSecurity(Transport.CONNECTION_SECURITY_NONE, false);
37596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        mSender.setTransport(mockTransport);
37696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return mockTransport;
37796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
37896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
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()
38196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *
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