michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: let test_generator = do_run_test(); michael@0: michael@0: function run_test() michael@0: { michael@0: do_test_pending(); michael@0: do_run_generator(test_generator); michael@0: } michael@0: michael@0: function continue_test() michael@0: { michael@0: do_run_generator(test_generator); michael@0: } michael@0: michael@0: function repeat_test() michael@0: { michael@0: // The test is probably going to fail because setting a batch of cookies took michael@0: // a significant fraction of 'gPurgeAge'. Compensate by rerunning the michael@0: // test with a larger purge age. michael@0: do_check_true(gPurgeAge < 64); michael@0: gPurgeAge *= 2; michael@0: gShortExpiry *= 2; michael@0: michael@0: do_execute_soon(function() { michael@0: test_generator.close(); michael@0: test_generator = do_run_test(); michael@0: do_run_generator(test_generator); michael@0: }); michael@0: } michael@0: michael@0: // Purge threshold, in seconds. michael@0: let gPurgeAge = 1; michael@0: michael@0: // Short expiry age, in seconds. michael@0: let gShortExpiry = 2; michael@0: michael@0: // Required delay to ensure a purge occurs, in milliseconds. This must be at michael@0: // least gPurgeAge + 10%, and includes a little fuzz to account for timer michael@0: // resolution and possible differences between PR_Now() and Date.now(). michael@0: function get_purge_delay() michael@0: { michael@0: return gPurgeAge * 1100 + 100; michael@0: } michael@0: michael@0: // Required delay to ensure a cookie set with an expiry time 'gShortExpiry' into michael@0: // the future will have expired. michael@0: function get_expiry_delay() michael@0: { michael@0: return gShortExpiry * 1000 + 100; michael@0: } michael@0: michael@0: function do_run_test() michael@0: { michael@0: // Set up a profile. michael@0: let profile = do_get_profile(); michael@0: michael@0: // twiddle prefs to convenient values for this test michael@0: Services.prefs.setIntPref("network.cookie.purgeAge", gPurgeAge); michael@0: Services.prefs.setIntPref("network.cookie.maxNumber", 100); michael@0: michael@0: let expiry = Date.now() / 1000 + 1000; michael@0: michael@0: // eviction is performed based on two limits: when the total number of cookies michael@0: // exceeds maxNumber + 10% (110), and when cookies are older than purgeAge michael@0: // (1 second). purging is done when both conditions are satisfied, and only michael@0: // those cookies are purged. michael@0: michael@0: // we test the following cases of eviction: michael@0: // 1) excess and age are satisfied, but only some of the excess are old enough michael@0: // to be purged. michael@0: Services.cookiemgr.removeAll(); michael@0: if (!set_cookies(0, 5, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: // Sleep a while, to make sure the first batch of cookies is older than michael@0: // the second (timer resolution varies on different platforms). michael@0: do_timeout(get_purge_delay(), continue_test); michael@0: yield; michael@0: if (!set_cookies(5, 111, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: michael@0: // Fake a profile change, to ensure eviction affects the database correctly. michael@0: do_close_profile(test_generator); michael@0: yield; michael@0: do_load_profile(); michael@0: do_check_true(check_remaining_cookies(111, 5, 106)); michael@0: michael@0: // 2) excess and age are satisfied, and all of the excess are old enough michael@0: // to be purged. michael@0: Services.cookiemgr.removeAll(); michael@0: if (!set_cookies(0, 10, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: do_timeout(get_purge_delay(), continue_test); michael@0: yield; michael@0: if (!set_cookies(10, 111, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: michael@0: do_close_profile(test_generator); michael@0: yield; michael@0: do_load_profile(); michael@0: do_check_true(check_remaining_cookies(111, 10, 101)); michael@0: michael@0: // 3) excess and age are satisfied, and more than the excess are old enough michael@0: // to be purged. michael@0: Services.cookiemgr.removeAll(); michael@0: if (!set_cookies(0, 50, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: do_timeout(get_purge_delay(), continue_test); michael@0: yield; michael@0: if (!set_cookies(50, 111, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: michael@0: do_close_profile(test_generator); michael@0: yield; michael@0: do_load_profile(); michael@0: do_check_true(check_remaining_cookies(111, 50, 101)); michael@0: michael@0: // 4) excess but not age are satisfied. michael@0: Services.cookiemgr.removeAll(); michael@0: if (!set_cookies(0, 120, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: michael@0: do_close_profile(test_generator); michael@0: yield; michael@0: do_load_profile(); michael@0: do_check_true(check_remaining_cookies(120, 0, 120)); michael@0: michael@0: // 5) age but not excess are satisfied. michael@0: Services.cookiemgr.removeAll(); michael@0: if (!set_cookies(0, 20, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: do_timeout(get_purge_delay(), continue_test); michael@0: yield; michael@0: if (!set_cookies(20, 110, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: michael@0: do_close_profile(test_generator); michael@0: yield; michael@0: do_load_profile(); michael@0: do_check_true(check_remaining_cookies(110, 20, 110)); michael@0: michael@0: // 6) Excess and age are satisfied, but the cookie limit can be satisfied by michael@0: // purging expired cookies. michael@0: Services.cookiemgr.removeAll(); michael@0: let shortExpiry = Math.floor(Date.now() / 1000) + gShortExpiry; michael@0: if (!set_cookies(0, 20, shortExpiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: do_timeout(get_expiry_delay(), continue_test); michael@0: yield; michael@0: if (!set_cookies(20, 110, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: do_timeout(get_purge_delay(), continue_test); michael@0: yield; michael@0: if (!set_cookies(110, 111, expiry)) { michael@0: repeat_test(); michael@0: return; michael@0: } michael@0: michael@0: do_close_profile(test_generator); michael@0: yield; michael@0: do_load_profile(); michael@0: do_check_true(check_remaining_cookies(111, 20, 91)); michael@0: michael@0: do_finish_generator_test(test_generator); michael@0: } michael@0: michael@0: // Set 'end - begin' total cookies, with consecutively increasing hosts numbered michael@0: // 'begin' to 'end'. michael@0: function set_cookies(begin, end, expiry) michael@0: { michael@0: do_check_true(begin != end); michael@0: michael@0: let beginTime; michael@0: for (let i = begin; i < end; ++i) { michael@0: let host = "eviction." + i + ".tests"; michael@0: Services.cookiemgr.add(host, "", "test", "eviction", false, false, false, michael@0: expiry); michael@0: michael@0: if (i == begin) michael@0: beginTime = get_creationTime(i); michael@0: } michael@0: michael@0: let endTime = get_creationTime(end - 1); michael@0: do_check_true(begin == end - 1 || endTime > beginTime); michael@0: if (endTime - beginTime > gPurgeAge * 1000000) { michael@0: // Setting cookies took an amount of time very close to the purge threshold. michael@0: // Retry the test with a larger threshold. michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: function get_creationTime(i) michael@0: { michael@0: let host = "eviction." + i + ".tests"; michael@0: let enumerator = Services.cookiemgr.getCookiesFromHost(host); michael@0: do_check_true(enumerator.hasMoreElements()); michael@0: let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); michael@0: return cookie.creationTime; michael@0: } michael@0: michael@0: // Test that 'aNumberToExpect' cookies remain after purging is complete, and michael@0: // that the cookies that remain consist of the set expected given the number of michael@0: // of older and newer cookies -- eviction should occur by order of lastAccessed michael@0: // time, if both the limit on total cookies (maxNumber + 10%) and the purge age michael@0: // + 10% are exceeded. michael@0: function check_remaining_cookies(aNumberTotal, aNumberOld, aNumberToExpect) { michael@0: var enumerator = Services.cookiemgr.enumerator; michael@0: michael@0: i = 0; michael@0: while (enumerator.hasMoreElements()) { michael@0: var cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); michael@0: ++i; michael@0: michael@0: if (aNumberTotal != aNumberToExpect) { michael@0: // make sure the cookie is one of the batch we expect was purged. michael@0: var hostNumber = new Number(cookie.rawHost.split(".")[1]); michael@0: if (hostNumber < (aNumberOld - aNumberToExpect)) break; michael@0: } michael@0: } michael@0: michael@0: return i == aNumberToExpect; michael@0: }