1 /* 2 * Copyright (C) 2009 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.browser; 18 19 import android.test.AndroidTestCase; 20 import android.test.suitebuilder.annotation.MediumTest; 21 import android.webkit.WebStorage; 22 23 /** 24 * This is a series of unit tests for the WebStorageSizeManager class. 25 * 26 */ 27 @MediumTest 28 public class WebStorageSizeManagerUnitTests extends AndroidTestCase { 29 // Used for testing the out-of-space callbacks. 30 private long mNewQuota; 31 // Callback functor that sets a new quota in case of out-of-space scenarios. 32 private class MockQuotaUpdater implements WebStorage.QuotaUpdater { 33 public void updateQuota(long newQuota) { 34 mNewQuota = newQuota; 35 } 36 } 37 38 // Mock the DiskInfo. 39 private class MockDiskInfo implements WebStorageSizeManager.DiskInfo { 40 private long mFreeSize; 41 private long mTotalSize; 42 43 public long getFreeSpaceSizeBytes() { 44 return mFreeSize; 45 } 46 47 public long getTotalSizeBytes() { 48 return mTotalSize; 49 } 50 51 public void setFreeSpaceSizeBytes(long freeSize) { 52 mFreeSize = freeSize; 53 } 54 55 public void setTotalSizeBytes(long totalSize) { 56 mTotalSize = totalSize; 57 } 58 } 59 60 // Mock the AppCacheInfo 61 public class MockAppCacheInfo implements WebStorageSizeManager.AppCacheInfo { 62 private long mAppCacheSize; 63 64 public long getAppCacheSizeBytes() { 65 return mAppCacheSize; 66 } 67 68 public void setAppCacheSizeBytes(long appCacheSize) { 69 mAppCacheSize = appCacheSize; 70 } 71 } 72 73 private MockQuotaUpdater mQuotaUpdater = new MockQuotaUpdater(); 74 private final MockDiskInfo mDiskInfo = new MockDiskInfo(); 75 private final MockAppCacheInfo mAppCacheInfo = new MockAppCacheInfo(); 76 // Utility for making size computations easier to read. 77 private long bytes(double megabytes) { 78 return (new Double(megabytes * 1024 * 1024)).longValue(); 79 } 80 /** 81 * Test the onExceededDatabaseQuota and onReachedMaxAppCacheSize callbacks 82 */ 83 public void testCallbacks() { 84 long totalUsedQuota = 0; 85 final long quotaIncrease = WebStorageSizeManager.QUOTA_INCREASE_STEP; // 1MB 86 87 // We have 75 MB total, 24MB free so the global limit will be 12 MB. 88 mDiskInfo.setTotalSizeBytes(bytes(75)); 89 mDiskInfo.setFreeSpaceSizeBytes(bytes(24)); 90 // We have an appcache file size of 0 MB. 91 mAppCacheInfo.setAppCacheSizeBytes(0); 92 // Create the manager. 93 WebStorageSizeManager manager = new WebStorageSizeManager(getContext(), mDiskInfo, 94 mAppCacheInfo); 95 // We add origin 1. 96 long origin1Quota = 0; 97 long origin1EstimatedSize = bytes(3.5); 98 manager.onExceededDatabaseQuota("1", "1", origin1Quota, origin1EstimatedSize, totalUsedQuota, mQuotaUpdater); 99 assertEquals(origin1EstimatedSize, mNewQuota); 100 origin1Quota = mNewQuota; 101 totalUsedQuota += origin1Quota; 102 103 // We add origin 2. 104 long origin2Quota = 0; 105 long origin2EstimatedSize = bytes(2.5); 106 manager.onExceededDatabaseQuota("2", "2", origin2Quota, origin2EstimatedSize, totalUsedQuota, mQuotaUpdater); 107 assertEquals(origin2EstimatedSize, mNewQuota); 108 origin2Quota = mNewQuota; 109 totalUsedQuota += origin2Quota; 110 111 // Origin 1 runs out of space. 112 manager.onExceededDatabaseQuota("1", "1", origin1Quota, 0, totalUsedQuota, mQuotaUpdater); 113 assertEquals(origin1EstimatedSize + quotaIncrease, mNewQuota); 114 totalUsedQuota -= origin1Quota; 115 origin1Quota = mNewQuota; 116 totalUsedQuota += origin1Quota; 117 118 // Origin 2 runs out of space. 119 manager.onExceededDatabaseQuota("2", "2", origin2Quota, 0, totalUsedQuota, mQuotaUpdater); 120 assertEquals(origin2EstimatedSize + quotaIncrease, mNewQuota); 121 totalUsedQuota -= origin2Quota; 122 origin2Quota = mNewQuota; 123 totalUsedQuota += origin2Quota; 124 125 // We add origin 3. TotalUsedQuota is 8 (3.5 + 2.5 + 1 + 1). AppCacheMaxSize is 3 (12 / 4). 126 // So we have 1 MB free. 127 long origin3Quota = 0; 128 long origin3EstimatedSize = bytes(5); 129 manager.onExceededDatabaseQuota("3", "3", origin3Quota, origin3EstimatedSize, totalUsedQuota, mQuotaUpdater); 130 assertEquals(0, mNewQuota); // We cannot satisfy the estimatedSize 131 origin3Quota = mNewQuota; 132 totalUsedQuota += origin3Quota; 133 134 // Origin 1 runs out of space again. It should increase it's quota to take the last 1MB. 135 manager.onExceededDatabaseQuota("1", "1", origin1Quota, 0, totalUsedQuota, mQuotaUpdater); 136 assertEquals(origin1Quota + quotaIncrease, mNewQuota); 137 totalUsedQuota -= origin1Quota; 138 origin1Quota = mNewQuota; 139 totalUsedQuota += origin1Quota; 140 141 // Origin 1 runs out of space again. It should inow fail to increase in size. 142 manager.onExceededDatabaseQuota("1", "1", origin1Quota, 0, totalUsedQuota, mQuotaUpdater); 143 assertEquals(origin1Quota, mNewQuota); 144 145 // We try adding a new origin. Which will fail. 146 manager.onExceededDatabaseQuota("4", "4", 0, bytes(1), totalUsedQuota, mQuotaUpdater); 147 assertEquals(0, mNewQuota); 148 149 // AppCache size increases to 2MB... 150 mAppCacheInfo.setAppCacheSizeBytes(bytes(2)); 151 // ... and wants 2MB more. Fail. 152 manager.onReachedMaxAppCacheSize(bytes(2), totalUsedQuota, mQuotaUpdater); 153 assertEquals(0, mNewQuota); 154 155 // The user nukes origin 2 156 totalUsedQuota -= origin2Quota; 157 origin2Quota = 0; 158 // TotalUsedQuota is 5.5 (9 - 3.5). AppCacheMaxSize is 3. AppCacheSize is 2. 159 // AppCache wants 1.5MB more 160 manager.onReachedMaxAppCacheSize(bytes(1.5), totalUsedQuota, mQuotaUpdater); 161 mAppCacheInfo.setAppCacheSizeBytes(mAppCacheInfo.getAppCacheSizeBytes() + bytes(2.5)); 162 assertEquals(mAppCacheInfo.getAppCacheSizeBytes(), mNewQuota - WebStorageSizeManager.APPCACHE_MAXSIZE_PADDING); 163 164 // We try adding a new origin. This time we succeed. 165 // TotalUsedQuota is 5.5. AppCacheMaxSize is 5.0. So we have 12 - 10.5 = 1.5 available. 166 long origin4Quota = 0; 167 long origin4EstimatedSize = bytes(1.5); 168 manager.onExceededDatabaseQuota("4", "4", origin4Quota, origin4EstimatedSize, totalUsedQuota, mQuotaUpdater); 169 assertEquals(bytes(1.5), mNewQuota); 170 origin4Quota = mNewQuota; 171 totalUsedQuota += origin4Quota; 172 } 173 /** 174 * Test the application caches max size calculator. 175 */ 176 public void testCalculateGlobalLimit() { 177 long fileSystemSize = 78643200; // 75 MB 178 long freeSpaceSize = 25165824; // 24 MB 179 long maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 180 assertEquals(12582912, maxSize); // 12MB 181 182 fileSystemSize = 78643200; // 75 MB 183 freeSpaceSize = 60 * 1024 * 1024; // 60MB 184 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 185 assertEquals(19922944, maxSize); // 19MB 186 187 fileSystemSize = 8589934592L; // 8 GB 188 freeSpaceSize = 4294967296L; // 4 GB 189 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 190 assertEquals(536870912L, maxSize); // 512 MB 191 192 fileSystemSize = -14; 193 freeSpaceSize = 21; 194 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 195 assertEquals(0, maxSize); 196 197 fileSystemSize = 100; 198 freeSpaceSize = 101; 199 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 200 assertEquals(0, maxSize); 201 202 fileSystemSize = 3774873; // ~4.2 MB 203 freeSpaceSize = 2560000; // ~2.4 MB 204 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 205 assertEquals(2097152, maxSize); // 2 MB 206 207 fileSystemSize = 4404019; // ~4.2 MB 208 freeSpaceSize = 3774873; // ~3.6 MB 209 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 210 assertEquals(2097152, maxSize); // 2 MB 211 212 fileSystemSize = 4404019; // ~4.2 MB 213 freeSpaceSize = 4404019; // ~4.2 MB 214 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 215 assertEquals(3145728, maxSize); // 3 MB 216 217 fileSystemSize = 1048576; // 1 MB 218 freeSpaceSize = 1048575; // 1 MB - 1 byte 219 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 220 assertEquals(0, maxSize); 221 222 fileSystemSize = 3774873; // ~3.6 MB 223 freeSpaceSize = 2097151; // 2 MB - 1 byte 224 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 225 assertEquals(0, maxSize); 226 227 fileSystemSize = 3774873; // ~3.6 MB 228 freeSpaceSize = 2097151; // 2 MB 229 maxSize = WebStorageSizeManager.calculateGlobalLimit(fileSystemSize, freeSpaceSize); 230 assertEquals(0, maxSize); 231 } 232 233 public void testManyDatabasesOnOneOrigin() { 234 // This test ensures that if an origin creates more than one database, the quota that is 235 // assigned to the origin after the second creation is enough to satisfy all databases 236 // under that origin. 237 // See b/2417477. 238 239 long totalUsedQuota = 0; 240 mDiskInfo.setTotalSizeBytes(bytes(100)); 241 mDiskInfo.setFreeSpaceSizeBytes(bytes(100)); 242 // This should give us a storage area of 13MB, with 3.25MB for appcache and 9.75MB for 243 // databases. 244 assertEquals(bytes(13), WebStorageSizeManager.calculateGlobalLimit( 245 mDiskInfo.getTotalSizeBytes(), mDiskInfo.getFreeSpaceSizeBytes())); 246 247 // We have an appcache file size of 0 MB. 248 mAppCacheInfo.setAppCacheSizeBytes(0); 249 250 // Create the manager. 251 WebStorageSizeManager manager = new WebStorageSizeManager(getContext(), mDiskInfo, 252 mAppCacheInfo); 253 254 // We add an origin. 255 long originQuota = 0; 256 long database1EstimatedSize = bytes(2); 257 manager.onExceededDatabaseQuota("1", "1", originQuota, database1EstimatedSize, 258 totalUsedQuota, mQuotaUpdater); 259 assertEquals(database1EstimatedSize, mNewQuota); 260 originQuota = mNewQuota; 261 totalUsedQuota = originQuota; 262 263 // Now try to create a new database under the origin, by invoking onExceededDatabaseQuota 264 // again. This time, request more space than the old quota + the quota increase step. 265 long database2EstimatedSize = bytes(3.5); 266 manager.onExceededDatabaseQuota("1", "2", originQuota, database2EstimatedSize, 267 totalUsedQuota, mQuotaUpdater); 268 assertEquals(database1EstimatedSize + database2EstimatedSize, mNewQuota); 269 originQuota = mNewQuota; 270 totalUsedQuota = originQuota; 271 272 // Create another database, but this time use a size that will overflow the space on the 273 // device. It should be denied. 274 long database3EstimatedSize = bytes(50); 275 manager.onExceededDatabaseQuota("1", "3", originQuota, database3EstimatedSize, 276 totalUsedQuota, mQuotaUpdater); 277 assertEquals(originQuota, mNewQuota); 278 279 // Create another database. This time, request less than the old quota. 280 long database4EstimatedSize = bytes(2); 281 manager.onExceededDatabaseQuota("1", "4", originQuota, database4EstimatedSize, 282 totalUsedQuota, mQuotaUpdater); 283 assertEquals(database1EstimatedSize + database2EstimatedSize + database4EstimatedSize, 284 mNewQuota); 285 originQuota = mNewQuota; 286 totalUsedQuota = originQuota; 287 288 // Now have the first database overflow it's quota. We should get 1 more MB. 289 manager.onExceededDatabaseQuota("1", "1", originQuota, 0, totalUsedQuota, mQuotaUpdater); 290 assertEquals(database1EstimatedSize + database2EstimatedSize + database4EstimatedSize + 291 bytes(1), mNewQuota); 292 originQuota = mNewQuota; 293 totalUsedQuota = originQuota; 294 295 // Create a db under the origin that uses a quota less than the usual quota increase step. 296 long database5EstimatedSize = bytes(0.5); 297 manager.onExceededDatabaseQuota("1", "5", originQuota, database5EstimatedSize, 298 totalUsedQuota, mQuotaUpdater); 299 assertEquals(database1EstimatedSize + database2EstimatedSize + database4EstimatedSize + 300 bytes(1) + database5EstimatedSize, mNewQuota); 301 } 302 } 303