Home | History | Annotate | Download | only in service
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.email.service;
     18 
     19 import android.content.Context;
     20 import android.content.Intent;
     21 
     22 import com.android.email.AccountTestCase;
     23 import com.android.email.EmailConnectivityManager;
     24 import com.android.email.provider.ProviderTestUtils;
     25 import com.android.email.service.AttachmentDownloadService.DownloadRequest;
     26 import com.android.email.service.AttachmentDownloadService.DownloadSet;
     27 import com.android.email.service.EmailServiceUtils.NullEmailService;
     28 import com.android.emailcommon.provider.Account;
     29 import com.android.emailcommon.provider.EmailContent.Attachment;
     30 import com.android.emailcommon.provider.EmailContent.Message;
     31 import com.android.emailcommon.provider.Mailbox;
     32 import com.android.emailcommon.service.EmailServiceStatus;
     33 
     34 import java.io.File;
     35 import java.util.Iterator;
     36 
     37 /**
     38  * Tests of the AttachmentDownloadService
     39  *
     40  * You can run this entire test case with:
     41  *   runtest -c com.android.email.service.AttachmentDownloadServiceTests email
     42  */
     43 public class AttachmentDownloadServiceTests extends AccountTestCase {
     44     private AttachmentDownloadService mService;
     45     private Context mMockContext;
     46     private Account mAccount;
     47     private Mailbox mMailbox;
     48     private long mAccountId;
     49     private long mMailboxId;
     50     private AttachmentDownloadService.AccountManagerStub mAccountManagerStub;
     51     private MockDirectory mMockDirectory;
     52 
     53     private DownloadSet mDownloadSet;
     54 
     55     @Override
     56     public void setUp() throws Exception {
     57         super.setUp();
     58         mMockContext = getMockContext();
     59 
     60         // Set up an account and mailbox
     61         mAccount = ProviderTestUtils.setupAccount("account", false, mMockContext);
     62         mAccount.mFlags |= Account.FLAGS_BACKGROUND_ATTACHMENTS;
     63         mAccount.save(mMockContext);
     64         mAccountId = mAccount.mId;
     65 
     66         mMailbox = ProviderTestUtils.setupMailbox("mailbox", mAccountId, true, mMockContext);
     67         mMailboxId = mMailbox.mId;
     68 
     69         // Set up our download service to simulate a running environment
     70         // Use the NullEmailService so that the loadAttachment calls become no-ops
     71         mService = new AttachmentDownloadService();
     72         mService.mContext = mMockContext;
     73         mService.addServiceIntentForTest(mAccountId, new Intent(mContext,
     74                 NullEmailService.class));
     75         mAccountManagerStub = new AttachmentDownloadService.AccountManagerStub(null);
     76         mService.mAccountManagerStub = mAccountManagerStub;
     77         mService.mConnectivityManager = new MockConnectivityManager(mContext, "mock");
     78         mDownloadSet = mService.mDownloadSet;
     79         mMockDirectory =
     80             new MockDirectory(mService.mContext.getCacheDir().getAbsolutePath());
     81     }
     82 
     83     @Override
     84     public void tearDown() throws Exception {
     85         super.tearDown();
     86     }
     87 
     88     /**
     89      * This test creates attachments and places them in the DownloadSet; we then do various checks
     90      * that exercise its functionality.
     91      */
     92     public void testDownloadSet() {
     93         // TODO: Make sure that this doesn't interfere with the "real" ADS that might be running
     94         // on device
     95         Message message = ProviderTestUtils.setupMessage("message", mAccountId, mMailboxId, false,
     96                 true, mMockContext);
     97         Attachment att1 = ProviderTestUtils.setupAttachment(message.mId, "filename1", 1000,
     98                 Attachment.FLAG_DOWNLOAD_USER_REQUEST, true, mMockContext);
     99         Attachment att2 = ProviderTestUtils.setupAttachment(message.mId, "filename2", 1000,
    100                 Attachment.FLAG_DOWNLOAD_FORWARD, true, mMockContext);
    101         Attachment att3 = ProviderTestUtils.setupAttachment(message.mId, "filename3", 1000,
    102                 Attachment.FLAG_DOWNLOAD_FORWARD, true, mMockContext);
    103         Attachment att4 = ProviderTestUtils.setupAttachment(message.mId, "filename4", 1000,
    104                 Attachment.FLAG_DOWNLOAD_USER_REQUEST, true, mMockContext);
    105         // Indicate that these attachments have changed; they will be added to the queue
    106         mDownloadSet.onChange(mMockContext, att1);
    107         mDownloadSet.onChange(mMockContext, att2);
    108         mDownloadSet.onChange(mMockContext, att3);
    109         mDownloadSet.onChange(mMockContext, att4);
    110         Iterator<DownloadRequest> iterator = mDownloadSet.descendingIterator();
    111         // Check the expected ordering; 1 & 4 are higher priority than 2 & 3
    112         // 1 and 3 were created earlier than their priority equals
    113         long[] expectedAttachmentIds = new long[] {att1.mId, att4.mId, att2.mId, att3.mId};
    114         for (int i = 0; i < expectedAttachmentIds.length; i++) {
    115             assertTrue(iterator.hasNext());
    116             DownloadRequest req = iterator.next();
    117             assertEquals(expectedAttachmentIds[i], req.attachmentId);
    118         }
    119 
    120         // Process the queue; attachment 1 should be marked "in progress", and should be in
    121         // the in-progress map
    122         mDownloadSet.createWatchdogPendingIntent(mContext);
    123         mDownloadSet.processQueue();
    124         DownloadRequest req = mDownloadSet.findDownloadRequest(att1.mId);
    125         assertNotNull(req);
    126         assertTrue(req.inProgress);
    127         assertTrue(mDownloadSet.mDownloadsInProgress.containsKey(att1.mId));
    128         // There should also be only one download in progress (testing the per-account limitation)
    129         assertEquals(1, mDownloadSet.mDownloadsInProgress.size());
    130         // End the "download" with a connection error; we should still have this in the queue,
    131         // but it should no longer be in-progress
    132         mDownloadSet.endDownload(att1.mId, EmailServiceStatus.CONNECTION_ERROR);
    133         assertFalse(req.inProgress);
    134         assertEquals(0, mDownloadSet.mDownloadsInProgress.size());
    135 
    136         mDownloadSet.processQueue();
    137         // Things should be as they were earlier; att1 should be an in-progress download
    138         req = mDownloadSet.findDownloadRequest(att1.mId);
    139         assertNotNull(req);
    140         assertTrue(req.inProgress);
    141         assertTrue(mDownloadSet.mDownloadsInProgress.containsKey(att1.mId));
    142         // Successfully download the attachment; there should be no downloads in progress, and
    143         // att1 should no longer be in the queue
    144         mDownloadSet.endDownload(att1.mId, EmailServiceStatus.SUCCESS);
    145         assertEquals(0, mDownloadSet.mDownloadsInProgress.size());
    146         assertNull(mDownloadSet.findDownloadRequest(att1.mId));
    147 
    148         // Test dequeue and isQueued
    149         assertEquals(3, mDownloadSet.size());
    150         mService.dequeue(att2.mId);
    151         assertEquals(2, mDownloadSet.size());
    152         assertTrue(mService.isQueued(att4.mId));
    153         assertTrue(mService.isQueued(att3.mId));
    154 
    155         mDownloadSet.processQueue();
    156         // att4 should be the download in progress
    157         req = mDownloadSet.findDownloadRequest(att4.mId);
    158         assertNotNull(req);
    159         assertTrue(req.inProgress);
    160         assertTrue(mDownloadSet.mDownloadsInProgress.containsKey(att4.mId));
    161     }
    162 
    163     /**
    164      * A mock file directory containing a single (Mock)File.  The total space, usable space, and
    165      * length of the single file can be set
    166      */
    167     private static class MockDirectory extends File {
    168         private static final long serialVersionUID = 1L;
    169         private long mTotalSpace;
    170         private long mUsableSpace;
    171         private MockFile[] mFiles;
    172         private final MockFile mMockFile = new MockFile();
    173 
    174 
    175         public MockDirectory(String path) {
    176             super(path);
    177             mFiles = new MockFile[1];
    178             mFiles[0] = mMockFile;
    179         }
    180 
    181         private void setTotalAndUsableSpace(long total, long usable) {
    182             mTotalSpace = total;
    183             mUsableSpace = usable;
    184         }
    185 
    186         public long getTotalSpace() {
    187             return mTotalSpace;
    188         }
    189 
    190         public long getUsableSpace() {
    191             return mUsableSpace;
    192         }
    193 
    194         public void setFileLength(long length) {
    195             mMockFile.mLength = length;
    196         }
    197 
    198         public File[] listFiles() {
    199             return mFiles;
    200         }
    201     }
    202 
    203     /**
    204      * A mock file that reports back a pre-set length
    205      */
    206     private static class MockFile extends File {
    207         private static final long serialVersionUID = 1L;
    208         private long mLength = 0;
    209 
    210         public MockFile() {
    211             super("_mock");
    212         }
    213 
    214         public long length() {
    215             return mLength;
    216         }
    217     }
    218 
    219     private static class MockConnectivityManager extends EmailConnectivityManager {
    220         public MockConnectivityManager(Context context, String name) {
    221             super(context, name);
    222         }
    223 
    224         @Override
    225         public void waitForConnectivity() {
    226         }
    227 
    228         @Override
    229         public boolean isAutoSyncAllowed() {
    230             return true;
    231         }
    232     }
    233 
    234     public void testCanPrefetchForAccount() {
    235         // First, test our "global" limits (based on free storage)
    236         // Mock storage @ 100 total and 26 available
    237         // Note that all file lengths in this test are in arbitrary units
    238         mMockDirectory.setTotalAndUsableSpace(100L, 26L);
    239         // Mock 2 accounts in total
    240         mAccountManagerStub.setNumberOfAccounts(2);
    241         // With 26% available, we should be ok to prefetch
    242         assertTrue(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    243         // Now change to 24 available
    244         mMockDirectory.setTotalAndUsableSpace(100L, 24L);
    245         // With 24% available, we should NOT be ok to prefetch
    246         assertFalse(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    247 
    248         // Now, test per-account storage
    249         // Mock storage @ 100 total and 50 available
    250         mMockDirectory.setTotalAndUsableSpace(100L, 50L);
    251         // Mock a file of length 12, but need to uncache previous amount first
    252         mService.mAttachmentStorageMap.remove(mAccountId);
    253         mMockDirectory.setFileLength(11);
    254         // We can prefetch since 11 < 50/4
    255         assertTrue(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    256         // Mock a file of length 13, but need to uncache previous amount first
    257         mService.mAttachmentStorageMap.remove(mAccountId);
    258         mMockDirectory.setFileLength(13);
    259         // We can't prefetch since 13 > 50/4
    260         assertFalse(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    261     }
    262 
    263     public void testCanPrefetchForAccountNoBackgroundDownload() {
    264         Account account = ProviderTestUtils.setupAccount("account2", false, mMockContext);
    265         account.mFlags &= ~Account.FLAGS_BACKGROUND_ATTACHMENTS;
    266         account.save(mMockContext);
    267 
    268         // First, test our "global" limits (based on free storage)
    269         // Mock storage @ 100 total and 26 available
    270         // Note that all file lengths in this test are in arbitrary units
    271         mMockDirectory.setTotalAndUsableSpace(100L, 26L);
    272         // Mock 2 accounts in total
    273         mAccountManagerStub.setNumberOfAccounts(2);
    274 
    275         // With 26% available, we should be ok to prefetch,
    276         // *but* bg download is disabled on the account.
    277         assertFalse(mService.canPrefetchForAccount(account, mMockDirectory));
    278     }
    279 }
    280