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.processQueue();
    123         DownloadRequest req = mDownloadSet.findDownloadRequest(att1.mId);
    124         assertNotNull(req);
    125         assertTrue(req.inProgress);
    126         assertTrue(mDownloadSet.mDownloadsInProgress.containsKey(att1.mId));
    127         // There should also be only one download in progress (testing the per-account limitation)
    128         assertEquals(1, mDownloadSet.mDownloadsInProgress.size());
    129         // End the "download" with a connection error; we should still have this in the queue,
    130         // but it should no longer be in-progress
    131         mDownloadSet.endDownload(att1.mId, EmailServiceStatus.CONNECTION_ERROR);
    132         assertFalse(req.inProgress);
    133         assertEquals(0, mDownloadSet.mDownloadsInProgress.size());
    134 
    135         mDownloadSet.processQueue();
    136         // Things should be as they were earlier; att1 should be an in-progress download
    137         req = mDownloadSet.findDownloadRequest(att1.mId);
    138         assertNotNull(req);
    139         assertTrue(req.inProgress);
    140         assertTrue(mDownloadSet.mDownloadsInProgress.containsKey(att1.mId));
    141         // Successfully download the attachment; there should be no downloads in progress, and
    142         // att1 should no longer be in the queue
    143         mDownloadSet.endDownload(att1.mId, EmailServiceStatus.SUCCESS);
    144         assertEquals(0, mDownloadSet.mDownloadsInProgress.size());
    145         assertNull(mDownloadSet.findDownloadRequest(att1.mId));
    146 
    147         // Test dequeue and isQueued
    148         assertEquals(3, mDownloadSet.size());
    149         mService.dequeue(att2.mId);
    150         assertEquals(2, mDownloadSet.size());
    151         assertTrue(mService.isQueued(att4.mId));
    152         assertTrue(mService.isQueued(att3.mId));
    153 
    154         mDownloadSet.processQueue();
    155         // att4 should be the download in progress
    156         req = mDownloadSet.findDownloadRequest(att4.mId);
    157         assertNotNull(req);
    158         assertTrue(req.inProgress);
    159         assertTrue(mDownloadSet.mDownloadsInProgress.containsKey(att4.mId));
    160     }
    161 
    162     /**
    163      * A mock file directory containing a single (Mock)File.  The total space, usable space, and
    164      * length of the single file can be set
    165      */
    166     private static class MockDirectory extends File {
    167         private static final long serialVersionUID = 1L;
    168         private long mTotalSpace;
    169         private long mUsableSpace;
    170         private MockFile[] mFiles;
    171         private final MockFile mMockFile = new MockFile();
    172 
    173 
    174         public MockDirectory(String path) {
    175             super(path);
    176             mFiles = new MockFile[1];
    177             mFiles[0] = mMockFile;
    178         }
    179 
    180         private void setTotalAndUsableSpace(long total, long usable) {
    181             mTotalSpace = total;
    182             mUsableSpace = usable;
    183         }
    184 
    185         @Override
    186         public long getTotalSpace() {
    187             return mTotalSpace;
    188         }
    189 
    190         @Override
    191         public long getUsableSpace() {
    192             return mUsableSpace;
    193         }
    194 
    195         public void setFileLength(long length) {
    196             mMockFile.mLength = length;
    197         }
    198 
    199         @Override
    200         public File[] listFiles() {
    201             return mFiles;
    202         }
    203     }
    204 
    205     /**
    206      * A mock file that reports back a pre-set length
    207      */
    208     private static class MockFile extends File {
    209         private static final long serialVersionUID = 1L;
    210         private long mLength = 0;
    211 
    212         public MockFile() {
    213             super("_mock");
    214         }
    215 
    216         @Override
    217         public long length() {
    218             return mLength;
    219         }
    220     }
    221 
    222     private static class MockConnectivityManager extends EmailConnectivityManager {
    223         public MockConnectivityManager(Context context, String name) {
    224             super(context, name);
    225         }
    226 
    227         @Override
    228         public void waitForConnectivity() {
    229         }
    230 
    231         @Override
    232         public boolean isAutoSyncAllowed() {
    233             return true;
    234         }
    235     }
    236 
    237     public void testCanPrefetchForAccount() {
    238         // First, test our "global" limits (based on free storage)
    239         // Mock storage @ 100 total and 26 available
    240         // Note that all file lengths in this test are in arbitrary units
    241         mMockDirectory.setTotalAndUsableSpace(100L, 26L);
    242         // Mock 2 accounts in total
    243         mAccountManagerStub.setNumberOfAccounts(2);
    244         // With 26% available, we should be ok to prefetch
    245         assertTrue(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    246         // Now change to 24 available
    247         mMockDirectory.setTotalAndUsableSpace(100L, 24L);
    248         // With 24% available, we should NOT be ok to prefetch
    249         assertFalse(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    250 
    251         // Now, test per-account storage
    252         // Mock storage @ 100 total and 50 available
    253         mMockDirectory.setTotalAndUsableSpace(100L, 50L);
    254         // Mock a file of length 12, but need to uncache previous amount first
    255         mService.mAttachmentStorageMap.remove(mAccountId);
    256         mMockDirectory.setFileLength(11);
    257         // We can prefetch since 11 < 50/4
    258         assertTrue(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    259         // Mock a file of length 13, but need to uncache previous amount first
    260         mService.mAttachmentStorageMap.remove(mAccountId);
    261         mMockDirectory.setFileLength(13);
    262         // We can't prefetch since 13 > 50/4
    263         assertFalse(mService.canPrefetchForAccount(mAccount, mMockDirectory));
    264     }
    265 
    266     public void testCanPrefetchForAccountNoBackgroundDownload() {
    267         Account account = ProviderTestUtils.setupAccount("account2", false, mMockContext);
    268         account.mFlags &= ~Account.FLAGS_BACKGROUND_ATTACHMENTS;
    269         account.save(mMockContext);
    270 
    271         // First, test our "global" limits (based on free storage)
    272         // Mock storage @ 100 total and 26 available
    273         // Note that all file lengths in this test are in arbitrary units
    274         mMockDirectory.setTotalAndUsableSpace(100L, 26L);
    275         // Mock 2 accounts in total
    276         mAccountManagerStub.setNumberOfAccounts(2);
    277 
    278         // With 26% available, we should be ok to prefetch,
    279         // *but* bg download is disabled on the account.
    280         assertFalse(mService.canPrefetchForAccount(account, mMockDirectory));
    281     }
    282 }
    283