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