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.test.suitebuilder.annotation.Suppress; 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.emailcommon.provider.Account; 28 import com.android.emailcommon.provider.EmailContent.Attachment; 29 import com.android.emailcommon.provider.EmailContent.Message; 30 import com.android.emailcommon.provider.Mailbox; 31 import com.android.emailcommon.service.EmailServiceStatus; 32 33 import java.io.File; 34 import java.util.Iterator; 35 36 /** 37 * Tests of the AttachmentDownloadService 38 * 39 * You can run this entire test case with: 40 * runtest -c com.android.email.service.AttachmentDownloadServiceTests email 41 */ 42 @Suppress 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 // there's no NullEmailService class 74 /*mService.addServiceIntentForTest(mAccountId, new Intent(mContext, 75 NullEmailService.class));*/ 76 mAccountManagerStub = new AttachmentDownloadService.AccountManagerStub(null); 77 mService.mAccountManagerStub = mAccountManagerStub; 78 mService.mConnectivityManager = new MockConnectivityManager(mContext, "mock"); 79 mDownloadSet = mService.mDownloadSet; 80 mMockDirectory = 81 new MockDirectory(mService.mContext.getCacheDir().getAbsolutePath()); 82 } 83 84 @Override 85 public void tearDown() throws Exception { 86 super.tearDown(); 87 } 88 89 /** 90 * This test creates attachments and places them in the DownloadSet; we then do various checks 91 * that exercise its functionality. 92 */ 93 public void testDownloadSet() { 94 // TODO: Make sure that this doesn't interfere with the "real" ADS that might be running 95 // on device 96 Message message = ProviderTestUtils.setupMessage("message", mAccountId, mMailboxId, false, 97 true, mMockContext); 98 Attachment att1 = ProviderTestUtils.setupAttachment(message.mId, "filename1", 1000, 99 Attachment.FLAG_DOWNLOAD_USER_REQUEST, true, mMockContext); 100 Attachment att2 = ProviderTestUtils.setupAttachment(message.mId, "filename2", 1000, 101 Attachment.FLAG_DOWNLOAD_FORWARD, true, mMockContext); 102 Attachment att3 = ProviderTestUtils.setupAttachment(message.mId, "filename3", 1000, 103 Attachment.FLAG_DOWNLOAD_FORWARD, true, mMockContext); 104 Attachment att4 = ProviderTestUtils.setupAttachment(message.mId, "filename4", 1000, 105 Attachment.FLAG_DOWNLOAD_USER_REQUEST, true, mMockContext); 106 // Indicate that these attachments have changed; they will be added to the queue 107 mDownloadSet.onChange(mMockContext, att1); 108 mDownloadSet.onChange(mMockContext, att2); 109 mDownloadSet.onChange(mMockContext, att3); 110 mDownloadSet.onChange(mMockContext, att4); 111 Iterator<DownloadRequest> iterator = mDownloadSet.descendingIterator(); 112 // Check the expected ordering; 1 & 4 are higher priority than 2 & 3 113 // 1 and 3 were created earlier than their priority equals 114 long[] expectedAttachmentIds = new long[] {att1.mId, att4.mId, att2.mId, att3.mId}; 115 for (int i = 0; i < expectedAttachmentIds.length; i++) { 116 assertTrue(iterator.hasNext()); 117 DownloadRequest req = iterator.next(); 118 assertEquals(expectedAttachmentIds[i], req.attachmentId); 119 } 120 121 // Process the queue; attachment 1 should be marked "in progress", and should be in 122 // the in-progress map 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 @Override 187 public long getTotalSpace() { 188 return mTotalSpace; 189 } 190 191 @Override 192 public long getUsableSpace() { 193 return mUsableSpace; 194 } 195 196 public void setFileLength(long length) { 197 mMockFile.mLength = length; 198 } 199 200 @Override 201 public File[] listFiles() { 202 return mFiles; 203 } 204 } 205 206 /** 207 * A mock file that reports back a pre-set length 208 */ 209 private static class MockFile extends File { 210 private static final long serialVersionUID = 1L; 211 private long mLength = 0; 212 213 public MockFile() { 214 super("_mock"); 215 } 216 217 @Override 218 public long length() { 219 return mLength; 220 } 221 } 222 223 private static class MockConnectivityManager extends EmailConnectivityManager { 224 public MockConnectivityManager(Context context, String name) { 225 super(context, name); 226 } 227 228 @Override 229 public void waitForConnectivity() { 230 } 231 232 @Override 233 public boolean isAutoSyncAllowed() { 234 return true; 235 } 236 } 237 238 public void testCanPrefetchForAccount() { 239 // First, test our "global" limits (based on free storage) 240 // Mock storage @ 100 total and 26 available 241 // Note that all file lengths in this test are in arbitrary units 242 mMockDirectory.setTotalAndUsableSpace(100L, 26L); 243 // Mock 2 accounts in total 244 mAccountManagerStub.setNumberOfAccounts(2); 245 // With 26% available, we should be ok to prefetch 246 assertTrue(mService.canPrefetchForAccount(mAccount, mMockDirectory)); 247 // Now change to 24 available 248 mMockDirectory.setTotalAndUsableSpace(100L, 24L); 249 // With 24% available, we should NOT be ok to prefetch 250 assertFalse(mService.canPrefetchForAccount(mAccount, mMockDirectory)); 251 252 // Now, test per-account storage 253 // Mock storage @ 100 total and 50 available 254 mMockDirectory.setTotalAndUsableSpace(100L, 50L); 255 // Mock a file of length 12, but need to uncache previous amount first 256 mService.mAttachmentStorageMap.remove(mAccountId); 257 mMockDirectory.setFileLength(11); 258 // We can prefetch since 11 < 50/4 259 assertTrue(mService.canPrefetchForAccount(mAccount, mMockDirectory)); 260 // Mock a file of length 13, but need to uncache previous amount first 261 mService.mAttachmentStorageMap.remove(mAccountId); 262 mMockDirectory.setFileLength(13); 263 // We can't prefetch since 13 > 50/4 264 assertFalse(mService.canPrefetchForAccount(mAccount, mMockDirectory)); 265 } 266 267 public void testCanPrefetchForAccountNoBackgroundDownload() { 268 Account account = ProviderTestUtils.setupAccount("account2", false, mMockContext); 269 account.mFlags &= ~Account.FLAGS_BACKGROUND_ATTACHMENTS; 270 account.save(mMockContext); 271 272 // First, test our "global" limits (based on free storage) 273 // Mock storage @ 100 total and 26 available 274 // Note that all file lengths in this test are in arbitrary units 275 mMockDirectory.setTotalAndUsableSpace(100L, 26L); 276 // Mock 2 accounts in total 277 mAccountManagerStub.setNumberOfAccounts(2); 278 279 // With 26% available, we should be ok to prefetch, 280 // *but* bg download is disabled on the account. 281 assertFalse(mService.canPrefetchForAccount(account, mMockDirectory)); 282 } 283 } 284