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 17package com.android.email.service; 18 19import android.content.Context; 20import android.content.Intent; 21 22import com.android.email.AccountTestCase; 23import com.android.email.EmailConnectivityManager; 24import com.android.email.provider.ProviderTestUtils; 25import com.android.email.service.AttachmentDownloadService.DownloadRequest; 26import com.android.email.service.AttachmentDownloadService.DownloadSet; 27import com.android.email.service.EmailServiceUtils.NullEmailService; 28import com.android.emailcommon.provider.Account; 29import com.android.emailcommon.provider.EmailContent.Attachment; 30import com.android.emailcommon.provider.EmailContent.Message; 31import com.android.emailcommon.provider.Mailbox; 32import com.android.emailcommon.service.EmailServiceStatus; 33 34import java.io.File; 35import 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 */ 43public 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