michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: // Test the various ways opening a cookie database can fail in a synchronous michael@0: // (i.e. immediate) manner, and that the database is renamed and recreated michael@0: // under each circumstance. These circumstances are, in no particular order: michael@0: // michael@0: // 1) A corrupt database, such that opening the connection fails. michael@0: // 2) The 'moz_cookies' table doesn't exist. michael@0: // 3) Not all of the expected columns exist, and statement creation fails when: michael@0: // a) The schema version is larger than the current version. michael@0: // b) The schema version is less than or equal to the current version. michael@0: // 4) Migration fails. This will have different modes depending on the initial michael@0: // version: michael@0: // a) Schema 1: the 'lastAccessed' column already exists. michael@0: // b) Schema 2: the 'baseDomain' column already exists; or 'baseDomain' michael@0: // cannot be computed for a particular host. michael@0: // c) Schema 3: the 'creationTime' column already exists; or the michael@0: // 'moz_uniqueid' index already exists. michael@0: michael@0: let COOKIE_DATABASE_SCHEMA_CURRENT = 5; michael@0: michael@0: let test_generator = do_run_test(); michael@0: michael@0: function run_test() { michael@0: do_test_pending(); michael@0: do_run_generator(test_generator); michael@0: } michael@0: michael@0: function finish_test() { michael@0: do_execute_soon(function() { michael@0: test_generator.close(); michael@0: do_test_finished(); michael@0: }); michael@0: } michael@0: michael@0: function do_run_test() { michael@0: // Set up a profile. michael@0: this.profile = do_get_profile(); michael@0: michael@0: // Allow all cookies. michael@0: Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); michael@0: michael@0: // Get the cookie file and the backup file. michael@0: this.cookieFile = profile.clone(); michael@0: cookieFile.append("cookies.sqlite"); michael@0: this.backupFile = profile.clone(); michael@0: backupFile.append("cookies.sqlite.bak"); michael@0: do_check_false(cookieFile.exists()); michael@0: do_check_false(backupFile.exists()); michael@0: michael@0: // Create a cookie object for testing. michael@0: this.now = Date.now() * 1000; michael@0: this.futureExpiry = Math.round(this.now / 1e6 + 1000); michael@0: this.cookie = new Cookie("oh", "hai", "bar.com", "/", this.futureExpiry, michael@0: this.now, this.now, false, false, false); michael@0: michael@0: this.sub_generator = run_test_1(test_generator); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_2(test_generator); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_3(test_generator, 99); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_3(test_generator, COOKIE_DATABASE_SCHEMA_CURRENT); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_3(test_generator, 4); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_3(test_generator, 3); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_4_exists(test_generator, 1, michael@0: "ALTER TABLE moz_cookies ADD lastAccessed INTEGER"); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_4_exists(test_generator, 2, michael@0: "ALTER TABLE moz_cookies ADD baseDomain TEXT"); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_4_baseDomain(test_generator); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_4_exists(test_generator, 3, michael@0: "ALTER TABLE moz_cookies ADD creationTime INTEGER"); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: this.sub_generator = run_test_4_exists(test_generator, 3, michael@0: "CREATE UNIQUE INDEX moz_uniqueid ON moz_cookies (name, host, path)"); michael@0: sub_generator.next(); michael@0: yield; michael@0: michael@0: finish_test(); michael@0: return; michael@0: } michael@0: michael@0: const garbage = "hello thar!"; michael@0: michael@0: function create_garbage_file(file) michael@0: { michael@0: // Create an empty database file. michael@0: file.create(Ci.nsIFile.NORMAL_FILE_TYPE, -1); michael@0: do_check_true(file.exists()); michael@0: do_check_eq(file.fileSize, 0); michael@0: michael@0: // Write some garbage to it. michael@0: let ostream = Cc["@mozilla.org/network/file-output-stream;1"]. michael@0: createInstance(Ci.nsIFileOutputStream); michael@0: ostream.init(file, -1, -1, 0); michael@0: ostream.write(garbage, garbage.length); michael@0: ostream.flush(); michael@0: ostream.close(); michael@0: michael@0: file = file.clone(); // Windows maintains a stat cache. It's lame. michael@0: do_check_eq(file.fileSize, garbage.length); michael@0: } michael@0: michael@0: function check_garbage_file(file) michael@0: { michael@0: do_check_true(file.exists()); michael@0: do_check_eq(file.fileSize, garbage.length); michael@0: file.remove(false); michael@0: do_check_false(file.exists()); michael@0: } michael@0: michael@0: function run_test_1(generator) michael@0: { michael@0: // Create a garbage database file. michael@0: create_garbage_file(cookieFile); michael@0: michael@0: // Load the profile and populate it. michael@0: let uri = NetUtil.newURI("http://foo.com/"); michael@0: Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); michael@0: michael@0: // Fake a profile change. michael@0: do_close_profile(sub_generator); michael@0: yield; michael@0: do_load_profile(); michael@0: michael@0: // Check that the new database contains the cookie, and the old file was michael@0: // renamed. michael@0: do_check_eq(do_count_cookies(), 1); michael@0: check_garbage_file(backupFile); michael@0: michael@0: // Close the profile. michael@0: do_close_profile(sub_generator); michael@0: yield; michael@0: michael@0: // Clean up. michael@0: cookieFile.remove(false); michael@0: do_check_false(cookieFile.exists()); michael@0: do_run_generator(generator); michael@0: } michael@0: michael@0: function run_test_2(generator) michael@0: { michael@0: // Load the profile and populate it. michael@0: do_load_profile(); michael@0: let uri = NetUtil.newURI("http://foo.com/"); michael@0: Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); michael@0: michael@0: // Fake a profile change. michael@0: do_close_profile(sub_generator); michael@0: yield; michael@0: michael@0: // Drop the table. michael@0: let db = Services.storage.openDatabase(cookieFile); michael@0: db.executeSimpleSQL("DROP TABLE moz_cookies"); michael@0: db.close(); michael@0: michael@0: // Load the profile and check that the table is recreated in-place. michael@0: do_load_profile(); michael@0: do_check_eq(do_count_cookies(), 0); michael@0: do_check_false(backupFile.exists()); michael@0: michael@0: // Close the profile. michael@0: do_close_profile(sub_generator); michael@0: yield; michael@0: michael@0: // Clean up. michael@0: cookieFile.remove(false); michael@0: do_check_false(cookieFile.exists()); michael@0: do_run_generator(generator); michael@0: } michael@0: michael@0: function run_test_3(generator, schema) michael@0: { michael@0: // Manually create a schema 2 database, populate it, and set the schema michael@0: // version to the desired number. michael@0: let schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); michael@0: schema2db.insertCookie(cookie); michael@0: schema2db.db.schemaVersion = schema; michael@0: schema2db.close(); michael@0: michael@0: // Load the profile and check that the column existence test fails. michael@0: do_load_profile(); michael@0: do_check_eq(do_count_cookies(), 0); michael@0: michael@0: // Close the profile. michael@0: do_close_profile(sub_generator); michael@0: yield; michael@0: michael@0: // Check that the schema version has been reset. michael@0: let db = Services.storage.openDatabase(cookieFile); michael@0: do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); michael@0: db.close(); michael@0: michael@0: // Clean up. michael@0: cookieFile.remove(false); michael@0: do_check_false(cookieFile.exists()); michael@0: do_run_generator(generator); michael@0: } michael@0: michael@0: function run_test_4_exists(generator, schema, stmt) michael@0: { michael@0: // Manually create a database, populate it, and add the desired column. michael@0: let db = new CookieDatabaseConnection(do_get_cookie_file(profile), schema); michael@0: db.insertCookie(cookie); michael@0: db.db.executeSimpleSQL(stmt); michael@0: db.close(); michael@0: michael@0: // Load the profile and check that migration fails. michael@0: do_load_profile(); michael@0: do_check_eq(do_count_cookies(), 0); michael@0: michael@0: // Close the profile. michael@0: do_close_profile(sub_generator); michael@0: yield; michael@0: michael@0: // Check that the schema version has been reset and the backup file exists. michael@0: db = Services.storage.openDatabase(cookieFile); michael@0: do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); michael@0: db.close(); michael@0: do_check_true(backupFile.exists()); michael@0: michael@0: // Clean up. michael@0: cookieFile.remove(false); michael@0: backupFile.remove(false); michael@0: do_check_false(cookieFile.exists()); michael@0: do_check_false(backupFile.exists()); michael@0: do_run_generator(generator); michael@0: } michael@0: michael@0: function run_test_4_baseDomain(generator) michael@0: { michael@0: // Manually create a database and populate it with a bad host. michael@0: let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); michael@0: let badCookie = new Cookie("oh", "hai", ".", "/", this.futureExpiry, this.now, michael@0: this.now, false, false, false); michael@0: db.insertCookie(badCookie); michael@0: db.close(); michael@0: michael@0: // Load the profile and check that migration fails. michael@0: do_load_profile(); michael@0: do_check_eq(do_count_cookies(), 0); michael@0: michael@0: // Close the profile. michael@0: do_close_profile(sub_generator); michael@0: yield; michael@0: michael@0: // Check that the schema version has been reset and the backup file exists. michael@0: db = Services.storage.openDatabase(cookieFile); michael@0: do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); michael@0: db.close(); michael@0: do_check_true(backupFile.exists()); michael@0: michael@0: // Clean up. michael@0: cookieFile.remove(false); michael@0: backupFile.remove(false); michael@0: do_check_false(cookieFile.exists()); michael@0: do_check_false(backupFile.exists()); michael@0: do_run_generator(generator); michael@0: }