test_eviction.js (6835B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 var test_generator = do_run_test(); 7 8 function run_test() { 9 do_test_pending(); 10 do_run_generator(test_generator); 11 } 12 13 function continue_test() { 14 do_run_generator(test_generator); 15 } 16 17 function repeat_test() { 18 // The test is probably going to fail because setting a batch of cookies took 19 // a significant fraction of 'gPurgeAge'. Compensate by rerunning the 20 // test with a larger purge age. 21 Assert.less(gPurgeAge, 64); 22 gPurgeAge *= 2; 23 gShortExpiry *= 2; 24 25 executeSoon(function () { 26 test_generator.return(); 27 test_generator = do_run_test(); 28 do_run_generator(test_generator); 29 }); 30 } 31 32 // Purge threshold, in seconds. 33 var gPurgeAge = 1; 34 35 // Short expiry age, in seconds. 36 var gShortExpiry = 2; 37 38 // Required delay to ensure a purge occurs, in milliseconds. This must be at 39 // least gPurgeAge + 10%, and includes a little fuzz to account for timer 40 // resolution and possible differences between PR_Now() and Date.now(). 41 function get_purge_delay() { 42 return gPurgeAge * 1100 + 100; 43 } 44 45 // Required delay to ensure a cookie set with an expiry time 'gShortExpiry' into 46 // the future will have expired. 47 function get_expiry_delay() { 48 return gShortExpiry * 1000 + 100; 49 } 50 51 function* do_run_test() { 52 // Set up a profile. 53 do_get_profile(); 54 55 // twiddle prefs to convenient values for this test 56 Services.prefs.setIntPref("network.cookie.purgeAge", gPurgeAge); 57 Services.prefs.setIntPref("network.cookie.maxNumber", 100); 58 59 let expiry = Date.now() + 1000 * 1000; 60 61 // eviction is performed based on two limits: when the total number of cookies 62 // exceeds maxNumber + 10% (110), and when cookies are older than purgeAge 63 // (1 second). purging is done when both conditions are satisfied, and only 64 // those cookies are purged. 65 66 // we test the following cases of eviction: 67 // 1) excess and age are satisfied, but only some of the excess are old enough 68 // to be purged. 69 Services.cookies.removeAll(); 70 if (!set_cookies(0, 5, expiry)) { 71 repeat_test(); 72 return; 73 } 74 // Sleep a while, to make sure the first batch of cookies is older than 75 // the second (timer resolution varies on different platforms). 76 do_timeout(get_purge_delay(), continue_test); 77 yield; 78 if (!set_cookies(5, 111, expiry)) { 79 repeat_test(); 80 return; 81 } 82 83 // Fake a profile change, to ensure eviction affects the database correctly. 84 do_close_profile(test_generator); 85 yield; 86 do_load_profile(); 87 Assert.ok(check_remaining_cookies(111, 5, 106)); 88 89 // 2) excess and age are satisfied, and all of the excess are old enough 90 // to be purged. 91 Services.cookies.removeAll(); 92 if (!set_cookies(0, 10, expiry)) { 93 repeat_test(); 94 return; 95 } 96 do_timeout(get_purge_delay(), continue_test); 97 yield; 98 if (!set_cookies(10, 111, expiry)) { 99 repeat_test(); 100 return; 101 } 102 103 do_close_profile(test_generator); 104 yield; 105 do_load_profile(); 106 Assert.ok(check_remaining_cookies(111, 10, 101)); 107 108 // 3) excess and age are satisfied, and more than the excess are old enough 109 // to be purged. 110 Services.cookies.removeAll(); 111 if (!set_cookies(0, 50, expiry)) { 112 repeat_test(); 113 return; 114 } 115 do_timeout(get_purge_delay(), continue_test); 116 yield; 117 if (!set_cookies(50, 111, expiry)) { 118 repeat_test(); 119 return; 120 } 121 122 do_close_profile(test_generator); 123 yield; 124 do_load_profile(); 125 Assert.ok(check_remaining_cookies(111, 50, 101)); 126 127 // 4) excess but not age are satisfied. 128 Services.cookies.removeAll(); 129 if (!set_cookies(0, 120, expiry)) { 130 repeat_test(); 131 return; 132 } 133 134 do_close_profile(test_generator); 135 yield; 136 do_load_profile(); 137 Assert.ok(check_remaining_cookies(120, 0, 120)); 138 139 // 5) age but not excess are satisfied. 140 Services.cookies.removeAll(); 141 if (!set_cookies(0, 20, expiry)) { 142 repeat_test(); 143 return; 144 } 145 do_timeout(get_purge_delay(), continue_test); 146 yield; 147 if (!set_cookies(20, 110, expiry)) { 148 repeat_test(); 149 return; 150 } 151 152 do_close_profile(test_generator); 153 yield; 154 do_load_profile(); 155 Assert.ok(check_remaining_cookies(110, 20, 110)); 156 157 // 6) Excess and age are satisfied, but the cookie limit can be satisfied by 158 // purging expired cookies. 159 Services.cookies.removeAll(); 160 let shortExpiry = Date.now() + 1000 * gShortExpiry; 161 if (!set_cookies(0, 20, shortExpiry)) { 162 repeat_test(); 163 return; 164 } 165 do_timeout(get_expiry_delay(), continue_test); 166 yield; 167 if (!set_cookies(20, 110, expiry)) { 168 repeat_test(); 169 return; 170 } 171 do_timeout(get_purge_delay(), continue_test); 172 yield; 173 if (!set_cookies(110, 111, expiry)) { 174 repeat_test(); 175 return; 176 } 177 178 do_close_profile(test_generator); 179 yield; 180 do_load_profile(); 181 Assert.ok(check_remaining_cookies(111, 20, 91)); 182 183 do_finish_generator_test(test_generator); 184 } 185 186 // Set 'end - begin' total cookies, with consecutively increasing hosts numbered 187 // 'begin' to 'end'. 188 function set_cookies(begin, end, expiry) { 189 Assert.notEqual(begin, end); 190 191 let beginTime; 192 for (let i = begin; i < end; ++i) { 193 let host = "eviction." + i + ".tests"; 194 const cv = Services.cookies.add( 195 host, 196 "", 197 "test", 198 "eviction", 199 false, 200 false, 201 false, 202 expiry, 203 {}, 204 Ci.nsICookie.SAMESITE_UNSET, 205 Ci.nsICookie.SCHEME_HTTPS 206 ); 207 Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie"); 208 209 if (i == begin) { 210 beginTime = get_creationTime(i); 211 } 212 } 213 214 let endTime = get_creationTime(end - 1); 215 Assert.ok(begin == end - 1 || endTime > beginTime); 216 if (endTime - beginTime > gPurgeAge * 1000000) { 217 // Setting cookies took an amount of time very close to the purge threshold. 218 // Retry the test with a larger threshold. 219 return false; 220 } 221 222 return true; 223 } 224 225 function get_creationTime(i) { 226 let host = "eviction." + i + ".tests"; 227 let cookies = Services.cookies.getCookiesFromHost(host, {}); 228 Assert.ok(cookies.length); 229 let cookie = cookies[0]; 230 return cookie.creationTime; 231 } 232 233 // Test that 'aNumberToExpect' cookies remain after purging is complete, and 234 // that the cookies that remain consist of the set expected given the number of 235 // of older and newer cookies -- eviction should occur by order of lastAccessed 236 // time, if both the limit on total cookies (maxNumber + 10%) and the purge age 237 // + 10% are exceeded. 238 function check_remaining_cookies(aNumberTotal, aNumberOld, aNumberToExpect) { 239 let i = 0; 240 for (let cookie of Services.cookies.cookies) { 241 ++i; 242 243 if (aNumberTotal != aNumberToExpect) { 244 // make sure the cookie is one of the batch we expect was purged. 245 var hostNumber = Number(cookie.rawHost.split(".")[1]); 246 if (hostNumber < aNumberOld - aNumberToExpect) { 247 break; 248 } 249 } 250 } 251 252 return i == aNumberToExpect; 253 }