• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.email.provider;
18 
19 import com.android.email.AttachmentInfo;
20 import com.android.email.R;
21 import com.android.emailcommon.mail.MessagingException;
22 import com.android.emailcommon.provider.Account;
23 import com.android.emailcommon.provider.EmailContent;
24 import com.android.emailcommon.provider.EmailContent.Attachment;
25 import com.android.emailcommon.provider.EmailContent.Message;
26 import com.android.emailcommon.provider.Mailbox;
27 import com.android.emailcommon.utility.AttachmentUtilities;
28 
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.res.AssetFileDescriptor;
32 import android.database.Cursor;
33 import android.graphics.Bitmap;
34 import android.graphics.BitmapFactory;
35 import android.net.Uri;
36 import android.test.ProviderTestCase2;
37 import android.test.mock.MockContentResolver;
38 
39 import java.io.File;
40 import java.io.FileNotFoundException;
41 import java.io.FileOutputStream;
42 import java.io.IOException;
43 
44 /**
45  * Tests of the Email Attachments provider.
46  *
47  * You can run this entire test case with:
48  *   runtest -c com.android.email.provider.AttachmentProviderTests email
49  */
50 public class AttachmentProviderTests extends ProviderTestCase2<AttachmentProvider> {
51 
52     EmailProvider mEmailProvider;
53     Context mMockContext;
54     ContentResolver mMockResolver;
55 
AttachmentProviderTests()56     public AttachmentProviderTests() {
57         super(AttachmentProvider.class, AttachmentUtilities.AUTHORITY);
58     }
59 
60     @Override
setUp()61     public void setUp() throws Exception {
62         super.setUp();
63         mMockContext = getMockContext();
64         mMockResolver = mMockContext.getContentResolver();
65 
66         // Spin up an Email provider as well and put it under the same mock test framework
67         mEmailProvider = new EmailProvider();
68         mEmailProvider.attachInfo(mMockContext, null);
69         assertNotNull(mEmailProvider);
70         ((MockContentResolver) mMockResolver)
71                 .addProvider(EmailContent.AUTHORITY, mEmailProvider);
72     }
73 
74     /**
75      * test delete() - should do nothing
76      * test update() - should do nothing
77      * test insert() - should do nothing
78      */
testUnimplemented()79     public void testUnimplemented() {
80         assertEquals(0, mMockResolver.delete(AttachmentUtilities.CONTENT_URI, null, null));
81         assertEquals(0, mMockResolver.update(AttachmentUtilities.CONTENT_URI, null, null,
82                 null));
83         assertEquals(null, mMockResolver.insert(AttachmentUtilities.CONTENT_URI, null));
84     }
85 
86     /**
87      * test query()
88      *  - item found
89      *  - item not found
90      *  - permuted projection
91      */
testQuery()92     public void testQuery() throws MessagingException {
93         Account account1 = ProviderTestUtils.setupAccount("attachment-query", false, mMockContext);
94         account1.mCompatibilityUuid = "test-UUID";
95         account1.save(mMockContext);
96         final long message1Id = 1;
97         long attachment1Id = 1;
98         long attachment2Id = 2;
99         long attachment3Id = 3;
100 
101         // Note:  There is an implicit assumption in this test sequence that the first
102         // attachment we add will be id=1 and the 2nd will have id=2.  This could fail on
103         // a legitimate implementation.  Asserts below will catch this and fail the test
104         // if necessary.
105         Uri attachment1Uri = AttachmentUtilities.getAttachmentUri(account1.mId,
106                 attachment1Id);
107         Uri attachment2Uri = AttachmentUtilities.getAttachmentUri(account1.mId,
108                 attachment2Id);
109         Uri attachment3Uri = AttachmentUtilities.getAttachmentUri(account1.mId,
110                 attachment3Id);
111 
112         // Test with no attachment found - should return null
113         Cursor c = mMockResolver.query(attachment1Uri, (String[])null, null, (String[])null, null);
114         assertNull(c);
115 
116         // Add a couple of attachment entries.  Note, query() just uses the DB, and does not
117         // sample the files, so we won't bother creating the files
118         Attachment newAttachment1 = ProviderTestUtils.setupAttachment(message1Id, "file1", 100,
119                 false, mMockContext);
120         newAttachment1.mContentUri =
121             AttachmentUtilities.getAttachmentUri(account1.mId, attachment1Id).toString();
122         attachment1Id = addAttachmentToDb(account1, newAttachment1);
123         assertEquals("Broken test:  Unexpected id assignment", 1, attachment1Id);
124 
125         Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file2", 200,
126                 false, mMockContext);
127         newAttachment2.mContentUri =
128             AttachmentUtilities.getAttachmentUri(account1.mId, attachment2Id).toString();
129         attachment2Id = addAttachmentToDb(account1, newAttachment2);
130         assertEquals("Broken test:  Unexpected id assignment", 2, attachment2Id);
131 
132         Attachment newAttachment3 = ProviderTestUtils.setupAttachment(message1Id, "file3", 300,
133                 false, mMockContext);
134         newAttachment3.mContentUri =
135             AttachmentUtilities.getAttachmentUri(account1.mId, attachment3Id).toString();
136         attachment3Id = addAttachmentToDb(account1, newAttachment3);
137         assertEquals("Broken test:  Unexpected id assignment", 3, attachment3Id);
138 
139         // Return a row with all columns specified
140         attachment2Uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment2Id);
141         c = mMockResolver.query(
142                 attachment2Uri,
143                 new String[] { AttachmentUtilities.Columns._ID,
144                                AttachmentUtilities.Columns.DATA,
145                                AttachmentUtilities.Columns.DISPLAY_NAME,
146                                AttachmentUtilities.Columns.SIZE },
147                 null, null, null);
148         assertEquals(1, c.getCount());
149         assertTrue(c.moveToFirst());
150         assertEquals(attachment2Id, c.getLong(0));                  // id
151         assertEquals(attachment2Uri.toString(), c.getString(1));    // content URI
152         assertEquals("file2", c.getString(2));                      // display name
153         assertEquals(200, c.getInt(3));                             // size
154 
155         // Return a row with permuted columns
156         attachment3Uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment3Id);
157         c = mMockResolver.query(
158                 attachment3Uri,
159                 new String[] { AttachmentUtilities.Columns.SIZE,
160                                AttachmentUtilities.Columns.DISPLAY_NAME,
161                                AttachmentUtilities.Columns.DATA,
162                                AttachmentUtilities.Columns._ID },
163                 null, null, null);
164         assertEquals(1, c.getCount());
165         assertTrue(c.moveToFirst());
166         assertEquals(attachment3Id, c.getLong(3));                  // id
167         assertEquals(attachment3Uri.toString(), c.getString(2));    // content URI
168         assertEquals("file3", c.getString(1));                      // display name
169         assertEquals(300, c.getInt(0));                             // size
170     }
171 
createMessage(Context c, Mailbox b)172     private static Message createMessage(Context c, Mailbox b) {
173         Message m = ProviderTestUtils.setupMessage("1", b.mAccountKey, b.mId, true, false, c, false,
174                 false);
175         m.mFlagLoaded = Message.FLAG_LOADED_COMPLETE;
176         m.save(c);
177         return m;
178     }
179 
testInboxQuery()180     public void testInboxQuery() {
181         // Create 2 accounts
182         Account a1 = ProviderTestUtils.setupAccount("inboxquery-1", true, mMockContext);
183         Account a2 = ProviderTestUtils.setupAccount("inboxquery-2", true, mMockContext);
184 
185         // Create mailboxes for each account
186         Mailbox b1 = ProviderTestUtils.setupMailbox(
187                 "box1", a1.mId, true, mMockContext, Mailbox.TYPE_INBOX);
188         Mailbox b2 = ProviderTestUtils.setupMailbox(
189                 "box2", a1.mId, true, mMockContext, Mailbox.TYPE_MAIL);
190         Mailbox b3 = ProviderTestUtils.setupMailbox(
191                 "box3", a2.mId, true, mMockContext, Mailbox.TYPE_INBOX);
192         Mailbox b4 = ProviderTestUtils.setupMailbox(
193                 "box4", a2.mId, true, mMockContext, Mailbox.TYPE_MAIL);
194         Mailbox bt = ProviderTestUtils.setupMailbox(
195                 "boxT", a2.mId, true, mMockContext, Mailbox.TYPE_TRASH);
196 
197         // Create some messages
198         // b1 (account 1, inbox): 2 messages
199         Message m11 = createMessage(mMockContext, b1);
200         Message m12 = createMessage(mMockContext, b1);
201 
202         // b2 (account 1, mail): 2 messages
203         Message m21 = createMessage(mMockContext, b2);
204         Message m22 = createMessage(mMockContext, b2);
205 
206         // b3 (account 2, inbox): 1 message
207         Message m31 = createMessage(mMockContext, b3);
208 
209         // b4 (account 2, mail) has no messages.
210 
211         // bt (account 2, trash): 1 message
212         Message mt1 = createMessage(mMockContext, bt);
213 
214         // 4 attachments in the inbox, 2 different messages, 1 downloaded
215         createAttachment(a1, m11.mId, null);
216         createAttachment(a1, m11.mId, null);
217         createAttachment(a1, m12.mId, null);
218         createAttachment(a1, m12.mId, "file:///path/to/file1");
219 
220         // 3 attachments in generic mailbox, 2 different messages, 1 downloaded
221         createAttachment(a1, m21.mId, null);
222         createAttachment(a1, m21.mId, null);
223         createAttachment(a1, m22.mId, null);
224         createAttachment(a1, m22.mId, "file:///path/to/file2");
225 
226         // 1 attachment in inbox
227         createAttachment(a2, m31.mId, null);
228 
229         // 2 attachments in trash, same message
230         createAttachment(a2, mt1.mId, null);
231         createAttachment(a2, mt1.mId, null);
232 
233         Cursor c = null;
234         try {
235             // count all attachments with an empty URI, regardless of mailbox location
236             c = mMockContext.getContentResolver().query(
237                     Attachment.CONTENT_URI, AttachmentInfo.PROJECTION,
238                     EmailContent.Attachment.PRECACHE_SELECTION,
239                     null, Attachment.RECORD_ID + " DESC");
240             assertEquals(9, c.getCount());
241         } finally {
242             c.close();
243         }
244 
245         try {
246             // count all attachments with an empty URI, only in an inbox
247             c = mMockContext.getContentResolver().query(
248                     Attachment.CONTENT_URI, AttachmentInfo.PROJECTION,
249                     EmailContent.Attachment.PRECACHE_INBOX_SELECTION,
250                     null, Attachment.RECORD_ID + " DESC");
251             assertEquals(4, c.getCount());
252         } finally {
253             c.close();
254         }
255     }
256 
257     /**
258      * test getType()
259      *  - regular file
260      *  - thumbnail
261      */
testGetType()262     public void testGetType() throws MessagingException {
263         Account account1 = ProviderTestUtils.setupAccount("get-type", false, mMockContext);
264         account1.mCompatibilityUuid = "test-UUID";
265         account1.save(mMockContext);
266         final long message1Id = 1;
267         long attachment1Id = 1;
268         long attachment2Id = 2;
269         long attachment3Id = 3;
270         long attachment4Id = 4;
271         long attachment5Id = 5;
272         long attachment6Id = 6;
273 
274         Uri attachment1Uri = AttachmentUtilities.getAttachmentUri(account1.mId,
275                 attachment1Id);
276 
277         // Test with no attachment found - should return null
278         String type = mMockResolver.getType(attachment1Uri);
279         assertNull(type);
280 
281         // Add a couple of attachment entries.  Note, getType() just uses the DB, and does not
282         // sample the files, so we won't bother creating the files
283         Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file2", 100,
284                 false, mMockContext);
285         newAttachment2.mMimeType = "image/jpg";
286         attachment2Id = addAttachmentToDb(account1, newAttachment2);
287 
288         Attachment newAttachment3 = ProviderTestUtils.setupAttachment(message1Id, "file3", 100,
289                 false, mMockContext);
290         newAttachment3.mMimeType = "text/plain";
291         attachment3Id = addAttachmentToDb(account1, newAttachment3);
292 
293         Attachment newAttachment4 = ProviderTestUtils.setupAttachment(message1Id, "file4.doc", 100,
294                 false, mMockContext);
295         newAttachment4.mMimeType = "application/octet-stream";
296         attachment4Id = addAttachmentToDb(account1, newAttachment4);
297 
298         Attachment newAttachment5 = ProviderTestUtils.setupAttachment(message1Id, "file5.xyz", 100,
299                 false, mMockContext);
300         newAttachment5.mMimeType = "application/octet-stream";
301         attachment5Id = addAttachmentToDb(account1, newAttachment5);
302 
303         Attachment newAttachment6 = ProviderTestUtils.setupAttachment(message1Id, "file6", 100,
304                 false, mMockContext);
305         newAttachment6.mMimeType = "";
306         attachment6Id = addAttachmentToDb(account1, newAttachment6);
307 
308         // Check the returned filetypes
309         Uri uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment2Id);
310         type = mMockResolver.getType(uri);
311         assertEquals("image/jpg", type);
312         uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment3Id);
313         type = mMockResolver.getType(uri);
314         assertEquals("text/plain", type);
315         uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment4Id);
316         type = mMockResolver.getType(uri);
317         assertEquals("application/msword", type);
318         uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment5Id);
319         type = mMockResolver.getType(uri);
320         assertEquals("application/xyz", type);
321         uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment6Id);
322         type = mMockResolver.getType(uri);
323         assertEquals("application/octet-stream", type);
324 
325         // Check the returned filetypes for the thumbnails
326         uri = AttachmentUtilities.getAttachmentThumbnailUri(account1.mId, attachment2Id, 62,
327                 62);
328         type = mMockResolver.getType(uri);
329         assertEquals("image/png", type);
330         uri = AttachmentUtilities.getAttachmentThumbnailUri(account1.mId, attachment3Id, 62,
331                 62);
332         type = mMockResolver.getType(uri);
333         assertEquals("image/png", type);
334     }
335 
336     /**
337      * test openFile()
338      *  - regular file
339      *  - TODO: variations on the content URI
340      */
testOpenFile()341     public void testOpenFile() throws MessagingException, IOException {
342         Account account1 = ProviderTestUtils.setupAccount("open-file", false, mMockContext);
343         account1.mCompatibilityUuid = "test-UUID";
344         account1.save(mMockContext);
345         final long message1Id = 1;
346         long attachment1Id = 1;
347         long attachment2Id = 2;
348 
349         // Note:  There is an implicit assumption in this test sequence that the first
350         // attachment we add will be id=1 and the 2nd will have id=2.  This could fail on
351         // a legitimate implementation.  Asserts below will catch this and fail the test
352         // if necessary.
353         Uri file1Uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment1Id);
354         Uri file2Uri = AttachmentUtilities.getAttachmentUri(account1.mId, attachment2Id);
355 
356         // Test with no attachment found
357         AssetFileDescriptor afd;
358         try {
359             afd = mMockResolver.openAssetFileDescriptor(file1Uri, "r");
360             fail("Should throw an exception on a missing attachment entry");
361         } catch (FileNotFoundException fnf) {
362             // expected
363         }
364 
365         // Add an attachment (but no associated file)
366         Attachment newAttachment = ProviderTestUtils.setupAttachment(message1Id, "file", 100,
367                 false, mMockContext);
368         attachment1Id = addAttachmentToDb(account1, newAttachment);
369         assertEquals("Broken test:  Unexpected id assignment", 1, attachment1Id);
370 
371         // Test with an attached database, attachment entry found, but no attachment found
372         try {
373             afd = mMockResolver.openAssetFileDescriptor(file1Uri, "r");
374             fail("Should throw an exception on a missing attachment file");
375         } catch (FileNotFoundException fnf) {
376             // expected
377         }
378 
379         // Create an "attachment" by copying an image resource into a file
380         /* String fileName = */ createAttachmentFile(account1, attachment2Id);
381         Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file", 100,
382                 false, mMockContext);
383         newAttachment2.mContentId = null;
384         newAttachment2.mContentUri =
385                 AttachmentUtilities.getAttachmentUri(account1.mId, attachment2Id)
386                 .toString();
387         newAttachment2.mMimeType = "image/png";
388         attachment2Id = addAttachmentToDb(account1, newAttachment2);
389         assertEquals("Broken test:  Unexpected id assignment", 2, attachment2Id);
390 
391         // Test with an attached database, attachment entry found - returns a file
392         afd = mMockResolver.openAssetFileDescriptor(file2Uri, "r");
393         assertNotNull(afd);
394         // TODO: Confirm it's the "right" file?
395         afd.close();
396     }
397 
398     /**
399      * test openFile()
400      *  - thumbnail
401      * @throws IOException
402      *
403      * TODO:  The thumbnail mode returns null for its failure cases (and in one case, throws
404      * an SQLiteException).  The ContentResolver contract requires throwing FileNotFoundException
405      * in all of the non-success cases, and the provider should be fixed for consistency.
406      */
testOpenThumbnail()407     public void testOpenThumbnail() throws MessagingException, IOException {
408         Account account1 = ProviderTestUtils.setupAccount("open-thumbnail", false, mMockContext);
409         account1.mCompatibilityUuid = "test-UUID";
410         account1.save(mMockContext);
411         final long message1Id = 1;
412         long attachment1Id = 1;
413         long attachment2Id = 2;
414 
415         // Note:  There is an implicit assumption in this test sequence that the first
416         // attachment we add will be id=1 and the 2nd will have id=2.  This could fail on
417         // a legitimate implementation.  Asserts below will catch this and fail the test
418         // if necessary.
419         Uri thumb1Uri = AttachmentUtilities.getAttachmentThumbnailUri(account1.mId,
420                 attachment1Id, 62, 62);
421         Uri thumb2Uri = AttachmentUtilities.getAttachmentThumbnailUri(account1.mId,
422                 attachment2Id, 62, 62);
423 
424         // Test with an attached database, but no attachment found
425         AssetFileDescriptor afd = mMockResolver.openAssetFileDescriptor(thumb1Uri, "r");
426         assertNull(afd);
427 
428         // Add an attachment (but no associated file)
429         Attachment newAttachment = ProviderTestUtils.setupAttachment(message1Id, "file", 100,
430                 false, mMockContext);
431         attachment1Id = addAttachmentToDb(account1, newAttachment);
432         assertEquals("Broken test:  Unexpected id assignment", 1, attachment1Id);
433 
434         // Test with an attached database, attachment entry found, but no attachment found
435         afd = mMockResolver.openAssetFileDescriptor(thumb1Uri, "r");
436         assertNull(afd);
437 
438         // Create an "attachment" by copying an image resource into a file
439         /* String fileName = */ createAttachmentFile(account1, attachment2Id);
440         Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file", 100,
441                 false, mMockContext);
442         newAttachment2.mContentId = null;
443         newAttachment2.mContentUri =
444                 AttachmentUtilities.getAttachmentUri(account1.mId, attachment2Id)
445                 .toString();
446         newAttachment2.mMimeType = "image/png";
447         attachment2Id = addAttachmentToDb(account1, newAttachment2);
448         assertEquals("Broken test:  Unexpected id assignment", 2, attachment2Id);
449 
450         // Test with an attached database, attachment entry found - returns a thumbnail
451         afd = mMockResolver.openAssetFileDescriptor(thumb2Uri, "r");
452         assertNotNull(afd);
453         // TODO: Confirm it's the "right" file?
454         afd.close();
455     }
456 
createAttachment(Account account, long messageId, String contentUriStr)457     private Uri createAttachment(Account account, long messageId, String contentUriStr) {
458         // Add an attachment entry.
459         Attachment newAttachment = ProviderTestUtils.setupAttachment(messageId, "file", 100,
460                 false, mMockContext);
461         newAttachment.mContentUri = contentUriStr;
462         long attachmentId = addAttachmentToDb(account, newAttachment);
463         Uri attachmentUri = AttachmentUtilities.getAttachmentUri(account.mId, attachmentId);
464         return attachmentUri;
465     }
466 
467     /**
468      * test resolveAttachmentIdToContentUri()
469      *  - without DB
470      *  - not in DB
471      *  - in DB, with not-null contentUri
472      *  - in DB, with null contentUri
473      */
testResolveAttachmentIdToContentUri()474     public void testResolveAttachmentIdToContentUri() throws MessagingException {
475         Account account1 = ProviderTestUtils.setupAccount("attachment-query", false, mMockContext);
476         account1.mCompatibilityUuid = "test-UUID";
477         account1.save(mMockContext);
478         final long message1Id = 1;
479         // We use attachmentId == 1 but any other id would do
480         final long attachment1Id = 1;
481         final Uri attachment1Uri = AttachmentUtilities.getAttachmentUri(account1.mId,
482                 attachment1Id);
483 
484         // Test with no attachment found - should return input
485         // We know that the attachmentId 1 does not exist because there are no attachments
486         // created at this point
487         Uri result = AttachmentUtilities.resolveAttachmentIdToContentUri(
488                 mMockResolver, attachment1Uri);
489         assertEquals(attachment1Uri, result);
490 
491         // Test with existing attachement and contentUri != null
492         // Note, resolveAttachmentIdToContentUri() just uses
493         // the DB, and does not sample the files, so we won't bother creating the files
494         {
495             Uri attachmentUri = createAttachment(account1, message1Id, "file:///path/to/file");
496             Uri contentUri = AttachmentUtilities.resolveAttachmentIdToContentUri(
497                     mMockResolver, attachmentUri);
498             // When the attachment is found, return the stored content_uri value
499             assertEquals("file:///path/to/file", contentUri.toString());
500         }
501 
502         // Test with existing attachement and contentUri == null
503         {
504             Uri attachmentUri = createAttachment(account1, message1Id, null);
505             Uri contentUri = AttachmentUtilities.resolveAttachmentIdToContentUri(
506                     mMockResolver, attachmentUri);
507             // When contentUri is null should return input
508             assertEquals(attachmentUri, contentUri);
509         }
510     }
511 
512     /**
513      * Test the functionality of deleting all attachment files for a given message.
514      */
testDeleteFiles()515     public void testDeleteFiles() throws IOException {
516         Account account1 = ProviderTestUtils.setupAccount("attachment-query", false, mMockContext);
517         account1.mCompatibilityUuid = "test-UUID";
518         account1.save(mMockContext);
519         final long message1Id = 1;      // 1 attachment, 1 file
520         final long message2Id = 2;      // 2 attachments, 2 files
521         final long message3Id = 3;      // 1 attachment, missing file
522         final long message4Id = 4;      // no attachments
523 
524         // Add attachment entries for various test messages
525         Attachment newAttachment1 = ProviderTestUtils.setupAttachment(message1Id, "file1", 100,
526                 true, mMockContext);
527         Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message2Id, "file2", 200,
528                 true, mMockContext);
529         Attachment newAttachment3 = ProviderTestUtils.setupAttachment(message2Id, "file3", 100,
530                 true, mMockContext);
531         Attachment newAttachment4 = ProviderTestUtils.setupAttachment(message3Id, "file4", 100,
532                 true, mMockContext);
533 
534         // Create test files
535         createAttachmentFile(account1, newAttachment1.mId);
536         createAttachmentFile(account1, newAttachment2.mId);
537         createAttachmentFile(account1, newAttachment3.mId);
538 
539         // Confirm 3 attachment files found
540         File attachmentsDir = AttachmentUtilities.getAttachmentDirectory(mMockContext,
541                 account1.mId);
542         assertEquals(3, attachmentsDir.listFiles().length);
543 
544         // Command deletion of some files and check for results
545 
546         // Message 4 has no attachments so no files should be deleted
547         AttachmentUtilities.deleteAllAttachmentFiles(mMockContext, account1.mId,
548                 message4Id);
549         assertEquals(3, attachmentsDir.listFiles().length);
550 
551         // Message 3 has no attachment files so no files should be deleted
552         AttachmentUtilities.deleteAllAttachmentFiles(mMockContext, account1.mId,
553                 message3Id);
554         assertEquals(3, attachmentsDir.listFiles().length);
555 
556         // Message 2 has 2 attachment files so this should delete 2 files
557         AttachmentUtilities.deleteAllAttachmentFiles(mMockContext, account1.mId,
558                 message2Id);
559         assertEquals(1, attachmentsDir.listFiles().length);
560 
561         // Message 1 has 1 attachment file so this should delete the last file
562         AttachmentUtilities.deleteAllAttachmentFiles(mMockContext, account1.mId,
563                 message1Id);
564         assertEquals(0, attachmentsDir.listFiles().length);
565     }
566 
567     /**
568      * Test the functionality of deleting an entire mailbox's attachments.
569      */
testDeleteMailbox()570     public void testDeleteMailbox() throws IOException {
571         Account account1 = ProviderTestUtils.setupAccount("attach-mbox-del", false, mMockContext);
572         account1.mCompatibilityUuid = "test-UUID";
573         account1.save(mMockContext);
574         long account1Id = account1.mId;
575         Mailbox mailbox1 = ProviderTestUtils.setupMailbox("mbox1", account1Id, true, mMockContext);
576         long mailbox1Id = mailbox1.mId;
577         Mailbox mailbox2 = ProviderTestUtils.setupMailbox("mbox2", account1Id, true, mMockContext);
578         long mailbox2Id = mailbox2.mId;
579 
580         // Fill each mailbox with messages & attachments
581         populateAccountMailbox(account1, mailbox1Id, 3);
582         populateAccountMailbox(account1, mailbox2Id, 1);
583 
584         // Confirm four attachment files found
585         File attachmentsDir = AttachmentUtilities.getAttachmentDirectory(mMockContext,
586                 account1.mId);
587         assertEquals(4, attachmentsDir.listFiles().length);
588 
589         // Command the deletion of mailbox 1 - we should lose 3 attachment files
590         AttachmentUtilities.deleteAllMailboxAttachmentFiles(mMockContext, account1Id,
591                 mailbox1Id);
592         assertEquals(1, attachmentsDir.listFiles().length);
593 
594         // Command the deletion of mailbox 2 - we should lose 1 attachment file
595         AttachmentUtilities.deleteAllMailboxAttachmentFiles(mMockContext, account1Id,
596                 mailbox2Id);
597         assertEquals(0, attachmentsDir.listFiles().length);
598     }
599 
600     /**
601      * Test the functionality of deleting an entire account's attachments.
602      */
testDeleteAccount()603     public void testDeleteAccount() throws IOException {
604         Account account1 = ProviderTestUtils.setupAccount("attach-acct-del1", false, mMockContext);
605         account1.mCompatibilityUuid = "test-UUID";
606         account1.save(mMockContext);
607         long account1Id = account1.mId;
608         Mailbox mailbox1 = ProviderTestUtils.setupMailbox("mbox1", account1Id, true, mMockContext);
609         long mailbox1Id = mailbox1.mId;
610         Mailbox mailbox2 = ProviderTestUtils.setupMailbox("mbox2", account1Id, true, mMockContext);
611         long mailbox2Id = mailbox2.mId;
612 
613         // Repeat for account #2
614         Account account2 = ProviderTestUtils.setupAccount("attach-acct-del2", false, mMockContext);
615         account2.mCompatibilityUuid = "test-UUID-2";
616         account2.save(mMockContext);
617         long account2Id = account2.mId;
618         Mailbox mailbox3 = ProviderTestUtils.setupMailbox("mbox3", account2Id, true, mMockContext);
619         long mailbox3Id = mailbox3.mId;
620         Mailbox mailbox4 = ProviderTestUtils.setupMailbox("mbox4", account2Id, true, mMockContext);
621         long mailbox4Id = mailbox4.mId;
622 
623         // Fill each mailbox with messages & attachments
624         populateAccountMailbox(account1, mailbox1Id, 3);
625         populateAccountMailbox(account1, mailbox2Id, 1);
626         populateAccountMailbox(account2, mailbox3Id, 5);
627         populateAccountMailbox(account2, mailbox4Id, 2);
628 
629         // Confirm eleven attachment files found
630         File directory1 = AttachmentUtilities.getAttachmentDirectory(mMockContext,
631                 account1.mId);
632         assertEquals(4, directory1.listFiles().length);
633         File directory2 = AttachmentUtilities.getAttachmentDirectory(mMockContext,
634                 account2.mId);
635         assertEquals(7, directory2.listFiles().length);
636 
637         // Command the deletion of account 1 - we should lose 4 attachment files
638         AttachmentUtilities.deleteAllAccountAttachmentFiles(mMockContext, account1Id);
639         assertEquals(0, directory1.listFiles().length);
640         assertEquals(7, directory2.listFiles().length);
641 
642         // Command the deletion of account 2 - we should lose 7 attachment file
643         AttachmentUtilities.deleteAllAccountAttachmentFiles(mMockContext, account2Id);
644         assertEquals(0, directory1.listFiles().length);
645         assertEquals(0, directory2.listFiles().length);
646     }
647 
648     /**
649      * Create a set of attachments for a given test account and mailbox.  Creates the following:
650      *  Two messages per mailbox, one w/attachments, one w/o attachments
651      *  Any number of attachments (on the first message)
652      *  @param account the account to populate
653      *  @param mailboxId the mailbox to populate
654      *  @param numAttachments how many attachments to create
655      */
populateAccountMailbox(Account account, long mailboxId, int numAttachments)656     private void populateAccountMailbox(Account account, long mailboxId, int numAttachments)
657             throws IOException {
658         long accountId = account.mId;
659 
660         // two messages per mailbox, one w/attachments, one w/o attachments
661         Message message1a = ProviderTestUtils.setupMessage(
662                 "msg1a", accountId, mailboxId, false, true, mMockContext);
663         /* Message message1b = */ ProviderTestUtils.setupMessage(
664                 "msg1b", accountId, mailboxId, false, true, mMockContext);
665 
666         // Create attachment records & files
667         for (int count = 0; count < numAttachments; count++) {
668             Attachment newAttachment = ProviderTestUtils.setupAttachment(message1a.mId,
669                     "file" + count, 100 * count, true, mMockContext);
670             createAttachmentFile(account, newAttachment.mId);
671         }
672     }
673 
674     /**
675      * Create an attachment by copying an image resource into a file.  Uses "real" resources
676      * to get a real image from Email
677      */
createAttachmentFile(Account forAccount, long id)678     private String createAttachmentFile(Account forAccount, long id) throws IOException {
679         File outFile = getAttachmentFile(forAccount, id);
680         Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(),
681                 R.drawable.ic_attachment_holo_light);
682         FileOutputStream out = new FileOutputStream(outFile);
683         bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
684         out.close();
685 
686         return outFile.getAbsolutePath();
687     }
688 
689     /**
690      * Record an attachment in the attachments database
691      * @return the id of the attachment just created
692      */
addAttachmentToDb(Account forAccount, Attachment newAttachment)693     private long addAttachmentToDb(Account forAccount, Attachment newAttachment) {
694         newAttachment.save(mMockContext);
695         return newAttachment.mId;
696     }
697 
698     /**
699      * Map from account, attachment ID to attachment file
700      */
getAttachmentFile(Account forAccount, long id)701     private File getAttachmentFile(Account forAccount, long id) {
702         String idString = Long.toString(id);
703         File attachmentsDir = mMockContext.getDatabasePath(forAccount.mId + ".db_att");
704         if (!attachmentsDir.exists()) {
705             attachmentsDir.mkdirs();
706         }
707         return new File(attachmentsDir, idString);
708     }
709 }
710