1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/storage/test/unit/test_vacuum.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,335 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ 1.6 + */ 1.7 + 1.8 +// This file tests the Vacuum Manager. 1.9 + 1.10 +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); 1.11 +Components.utils.import("resource://gre/modules/Services.jsm"); 1.12 + 1.13 +/** 1.14 + * Loads a test component that will register as a vacuum-participant. 1.15 + * If other participants are found they will be unregistered, to avoid conflicts 1.16 + * with the test itself. 1.17 + */ 1.18 +function load_test_vacuum_component() 1.19 +{ 1.20 + const CATEGORY_NAME = "vacuum-participant"; 1.21 + 1.22 + do_load_manifest("vacuumParticipant.manifest"); 1.23 + 1.24 + // This is a lazy check, there could be more participants than just this test 1.25 + // we just mind that the test exists though. 1.26 + const EXPECTED_ENTRIES = ["vacuumParticipant"]; 1.27 + let catMan = Cc["@mozilla.org/categorymanager;1"]. 1.28 + getService(Ci.nsICategoryManager); 1.29 + let found = false; 1.30 + let entries = catMan.enumerateCategory(CATEGORY_NAME); 1.31 + while (entries.hasMoreElements()) { 1.32 + let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; 1.33 + print("Check if the found category entry (" + entry + ") is expected."); 1.34 + if (EXPECTED_ENTRIES.indexOf(entry) != -1) { 1.35 + print("Check that only one test entry exists."); 1.36 + do_check_false(found); 1.37 + found = true; 1.38 + } 1.39 + else { 1.40 + // Temporary unregister other participants for this test. 1.41 + catMan.deleteCategoryEntry("vacuum-participant", entry, false); 1.42 + } 1.43 + } 1.44 + print("Check the test entry exists."); 1.45 + do_check_true(found); 1.46 +} 1.47 + 1.48 +/** 1.49 + * Sends a fake idle-daily notification to the VACUUM Manager. 1.50 + */ 1.51 +function synthesize_idle_daily() 1.52 +{ 1.53 + let vm = Cc["@mozilla.org/storage/vacuum;1"].getService(Ci.nsIObserver); 1.54 + vm.observe(null, "idle-daily", null); 1.55 +} 1.56 + 1.57 +/** 1.58 + * Returns a new nsIFile reference for a profile database. 1.59 + * @param filename for the database, excluded the .sqlite extension. 1.60 + */ 1.61 +function new_db_file(name) 1.62 +{ 1.63 + let file = Services.dirsvc.get("ProfD", Ci.nsIFile); 1.64 + file.append(name + ".sqlite"); 1.65 + return file; 1.66 +} 1.67 + 1.68 +function run_test() 1.69 +{ 1.70 + do_test_pending(); 1.71 + 1.72 + // Change initial page size. Do it immediately since it would require an 1.73 + // additional vacuum op to do it later. As a bonus this makes the page size 1.74 + // change test really fast since it only has to check results. 1.75 + let conn = getDatabase(new_db_file("testVacuum")); 1.76 + conn.executeSimpleSQL("PRAGMA page_size = 1024"); 1.77 + print("Check current page size."); 1.78 + let stmt = conn.createStatement("PRAGMA page_size"); 1.79 + try { 1.80 + while (stmt.executeStep()) { 1.81 + do_check_eq(stmt.row.page_size, 1024); 1.82 + } 1.83 + } 1.84 + finally { 1.85 + stmt.finalize(); 1.86 + } 1.87 + 1.88 + load_test_vacuum_component(); 1.89 + 1.90 + run_next_test(); 1.91 +} 1.92 + 1.93 +function run_next_test() 1.94 +{ 1.95 + if (TESTS.length == 0) { 1.96 + Services.obs.notifyObservers(null, "test-options", "dispose"); 1.97 + do_test_finished(); 1.98 + } 1.99 + else { 1.100 + // Set last VACUUM to a date in the past. 1.101 + Services.prefs.setIntPref("storage.vacuum.last.testVacuum.sqlite", 1.102 + parseInt(Date.now() / 1000 - 31 * 86400)); 1.103 + do_execute_soon(TESTS.shift()); 1.104 + } 1.105 +} 1.106 + 1.107 +const TESTS = [ 1.108 + 1.109 +function test_common_vacuum() 1.110 +{ 1.111 + print("\n*** Test that a VACUUM correctly happens and all notifications are fired."); 1.112 + // Wait for VACUUM begin. 1.113 + let beginVacuumReceived = false; 1.114 + Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) { 1.115 + Services.obs.removeObserver(onVacuum, aTopic); 1.116 + beginVacuumReceived = true; 1.117 + }, "test-begin-vacuum", false); 1.118 + 1.119 + // Wait for heavy IO notifications. 1.120 + let heavyIOTaskBeginReceived = false; 1.121 + let heavyIOTaskEndReceived = false; 1.122 + Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) { 1.123 + if (heavyIOTaskBeginReceived && heavyIOTaskEndReceived) { 1.124 + Services.obs.removeObserver(onVacuum, aTopic); 1.125 + } 1.126 + 1.127 + if (aData == "vacuum-begin") { 1.128 + heavyIOTaskBeginReceived = true; 1.129 + } 1.130 + else if (aData == "vacuum-end") { 1.131 + heavyIOTaskEndReceived = true; 1.132 + } 1.133 + }, "heavy-io-task", false); 1.134 + 1.135 + // Wait for VACUUM end. 1.136 + Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) { 1.137 + Services.obs.removeObserver(onVacuum, aTopic); 1.138 + print("Check we received onBeginVacuum"); 1.139 + do_check_true(beginVacuumReceived); 1.140 + print("Check we received heavy-io-task notifications"); 1.141 + do_check_true(heavyIOTaskBeginReceived); 1.142 + do_check_true(heavyIOTaskEndReceived); 1.143 + print("Received onEndVacuum"); 1.144 + run_next_test(); 1.145 + }, "test-end-vacuum", false); 1.146 + 1.147 + synthesize_idle_daily(); 1.148 +}, 1.149 + 1.150 +function test_skipped_if_recent_vacuum() 1.151 +{ 1.152 + print("\n*** Test that a VACUUM is skipped if it was run recently."); 1.153 + Services.prefs.setIntPref("storage.vacuum.last.testVacuum.sqlite", 1.154 + parseInt(Date.now() / 1000)); 1.155 + 1.156 + // Wait for VACUUM begin. 1.157 + let vacuumObserver = { 1.158 + gotNotification: false, 1.159 + observe: function VO_observe(aSubject, aTopic, aData) { 1.160 + this.gotNotification = true; 1.161 + }, 1.162 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) 1.163 + } 1.164 + Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false); 1.165 + 1.166 + // Check after a couple seconds that no VACUUM has been run. 1.167 + do_timeout(2000, function () { 1.168 + print("Check VACUUM did not run."); 1.169 + do_check_false(vacuumObserver.gotNotification); 1.170 + Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum"); 1.171 + run_next_test(); 1.172 + }); 1.173 + 1.174 + synthesize_idle_daily(); 1.175 +}, 1.176 + 1.177 +function test_page_size_change() 1.178 +{ 1.179 + print("\n*** Test that a VACUUM changes page_size"); 1.180 + 1.181 + // We did setup the database with a small page size, the previous vacuum 1.182 + // should have updated it. 1.183 + print("Check that page size was updated."); 1.184 + let conn = getDatabase(new_db_file("testVacuum")); 1.185 + let stmt = conn.createStatement("PRAGMA page_size"); 1.186 + try { 1.187 + while (stmt.executeStep()) { 1.188 + do_check_eq(stmt.row.page_size, conn.defaultPageSize); 1.189 + } 1.190 + } 1.191 + finally { 1.192 + stmt.finalize(); 1.193 + } 1.194 + 1.195 + run_next_test(); 1.196 +}, 1.197 + 1.198 +function test_skipped_optout_vacuum() 1.199 +{ 1.200 + print("\n*** Test that a VACUUM is skipped if the participant wants to opt-out."); 1.201 + Services.obs.notifyObservers(null, "test-options", "opt-out"); 1.202 + 1.203 + // Wait for VACUUM begin. 1.204 + let vacuumObserver = { 1.205 + gotNotification: false, 1.206 + observe: function VO_observe(aSubject, aTopic, aData) { 1.207 + this.gotNotification = true; 1.208 + }, 1.209 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) 1.210 + } 1.211 + Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false); 1.212 + 1.213 + // Check after a couple seconds that no VACUUM has been run. 1.214 + do_timeout(2000, function () { 1.215 + print("Check VACUUM did not run."); 1.216 + do_check_false(vacuumObserver.gotNotification); 1.217 + Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum"); 1.218 + run_next_test(); 1.219 + }); 1.220 + 1.221 + synthesize_idle_daily(); 1.222 +}, 1.223 + 1.224 +/* Changing page size on WAL is not supported till Bug 634374 is properly fixed. 1.225 +function test_page_size_change_with_wal() 1.226 +{ 1.227 + print("\n*** Test that a VACUUM changes page_size with WAL mode"); 1.228 + Services.obs.notifyObservers(null, "test-options", "wal"); 1.229 + 1.230 + // Set a small page size. 1.231 + let conn = getDatabase(new_db_file("testVacuum2")); 1.232 + conn.executeSimpleSQL("PRAGMA page_size = 1024"); 1.233 + let stmt = conn.createStatement("PRAGMA page_size"); 1.234 + try { 1.235 + while (stmt.executeStep()) { 1.236 + do_check_eq(stmt.row.page_size, 1024); 1.237 + } 1.238 + } 1.239 + finally { 1.240 + stmt.finalize(); 1.241 + } 1.242 + 1.243 + // Use WAL journal mode. 1.244 + conn.executeSimpleSQL("PRAGMA journal_mode = WAL"); 1.245 + stmt = conn.createStatement("PRAGMA journal_mode"); 1.246 + try { 1.247 + while (stmt.executeStep()) { 1.248 + do_check_eq(stmt.row.journal_mode, "wal"); 1.249 + } 1.250 + } 1.251 + finally { 1.252 + stmt.finalize(); 1.253 + } 1.254 + 1.255 + // Wait for VACUUM end. 1.256 + let vacuumObserver = { 1.257 + observe: function VO_observe(aSubject, aTopic, aData) { 1.258 + Services.obs.removeObserver(this, aTopic); 1.259 + print("Check page size has been updated."); 1.260 + let stmt = conn.createStatement("PRAGMA page_size"); 1.261 + try { 1.262 + while (stmt.executeStep()) { 1.263 + do_check_eq(stmt.row.page_size, Ci.mozIStorageConnection.DEFAULT_PAGE_SIZE); 1.264 + } 1.265 + } 1.266 + finally { 1.267 + stmt.finalize(); 1.268 + } 1.269 + 1.270 + print("Check journal mode has been restored."); 1.271 + stmt = conn.createStatement("PRAGMA journal_mode"); 1.272 + try { 1.273 + while (stmt.executeStep()) { 1.274 + do_check_eq(stmt.row.journal_mode, "wal"); 1.275 + } 1.276 + } 1.277 + finally { 1.278 + stmt.finalize(); 1.279 + } 1.280 + 1.281 + run_next_test(); 1.282 + }, 1.283 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) 1.284 + } 1.285 + Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false); 1.286 + 1.287 + synthesize_idle_daily(); 1.288 +}, 1.289 +*/ 1.290 + 1.291 +function test_memory_database_crash() 1.292 +{ 1.293 + print("\n*** Test that we don't crash trying to vacuum a memory database"); 1.294 + Services.obs.notifyObservers(null, "test-options", "memory"); 1.295 + 1.296 + // Wait for VACUUM begin. 1.297 + let vacuumObserver = { 1.298 + gotNotification: false, 1.299 + observe: function VO_observe(aSubject, aTopic, aData) { 1.300 + this.gotNotification = true; 1.301 + }, 1.302 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) 1.303 + } 1.304 + Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false); 1.305 + 1.306 + // Check after a couple seconds that no VACUUM has been run. 1.307 + do_timeout(2000, function () { 1.308 + print("Check VACUUM did not run."); 1.309 + do_check_false(vacuumObserver.gotNotification); 1.310 + Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum"); 1.311 + run_next_test(); 1.312 + }); 1.313 + 1.314 + synthesize_idle_daily(); 1.315 +}, 1.316 + 1.317 +/* Changing page size on WAL is not supported till Bug 634374 is properly fixed. 1.318 +function test_wal_restore_fail() 1.319 +{ 1.320 + print("\n*** Test that a failing WAL restoration notifies failure"); 1.321 + Services.obs.notifyObservers(null, "test-options", "wal-fail"); 1.322 + 1.323 + // Wait for VACUUM end. 1.324 + let vacuumObserver = { 1.325 + observe: function VO_observe(aSubject, aTopic, aData) { 1.326 + Services.obs.removeObserver(vacuumObserver, "test-end-vacuum"); 1.327 + print("Check WAL restoration failed."); 1.328 + do_check_false(aData); 1.329 + run_next_test(); 1.330 + }, 1.331 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) 1.332 + } 1.333 + Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false); 1.334 + 1.335 + synthesize_idle_daily(); 1.336 +}, 1.337 +*/ 1.338 +];