1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/extensions/cookie/test/unit/test_cookies_sync_failure.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,286 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +// Test the various ways opening a cookie database can fail in a synchronous 1.8 +// (i.e. immediate) manner, and that the database is renamed and recreated 1.9 +// under each circumstance. These circumstances are, in no particular order: 1.10 +// 1.11 +// 1) A corrupt database, such that opening the connection fails. 1.12 +// 2) The 'moz_cookies' table doesn't exist. 1.13 +// 3) Not all of the expected columns exist, and statement creation fails when: 1.14 +// a) The schema version is larger than the current version. 1.15 +// b) The schema version is less than or equal to the current version. 1.16 +// 4) Migration fails. This will have different modes depending on the initial 1.17 +// version: 1.18 +// a) Schema 1: the 'lastAccessed' column already exists. 1.19 +// b) Schema 2: the 'baseDomain' column already exists; or 'baseDomain' 1.20 +// cannot be computed for a particular host. 1.21 +// c) Schema 3: the 'creationTime' column already exists; or the 1.22 +// 'moz_uniqueid' index already exists. 1.23 + 1.24 +let COOKIE_DATABASE_SCHEMA_CURRENT = 5; 1.25 + 1.26 +let test_generator = do_run_test(); 1.27 + 1.28 +function run_test() { 1.29 + do_test_pending(); 1.30 + do_run_generator(test_generator); 1.31 +} 1.32 + 1.33 +function finish_test() { 1.34 + do_execute_soon(function() { 1.35 + test_generator.close(); 1.36 + do_test_finished(); 1.37 + }); 1.38 +} 1.39 + 1.40 +function do_run_test() { 1.41 + // Set up a profile. 1.42 + this.profile = do_get_profile(); 1.43 + 1.44 + // Allow all cookies. 1.45 + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); 1.46 + 1.47 + // Get the cookie file and the backup file. 1.48 + this.cookieFile = profile.clone(); 1.49 + cookieFile.append("cookies.sqlite"); 1.50 + this.backupFile = profile.clone(); 1.51 + backupFile.append("cookies.sqlite.bak"); 1.52 + do_check_false(cookieFile.exists()); 1.53 + do_check_false(backupFile.exists()); 1.54 + 1.55 + // Create a cookie object for testing. 1.56 + this.now = Date.now() * 1000; 1.57 + this.futureExpiry = Math.round(this.now / 1e6 + 1000); 1.58 + this.cookie = new Cookie("oh", "hai", "bar.com", "/", this.futureExpiry, 1.59 + this.now, this.now, false, false, false); 1.60 + 1.61 + this.sub_generator = run_test_1(test_generator); 1.62 + sub_generator.next(); 1.63 + yield; 1.64 + 1.65 + this.sub_generator = run_test_2(test_generator); 1.66 + sub_generator.next(); 1.67 + yield; 1.68 + 1.69 + this.sub_generator = run_test_3(test_generator, 99); 1.70 + sub_generator.next(); 1.71 + yield; 1.72 + 1.73 + this.sub_generator = run_test_3(test_generator, COOKIE_DATABASE_SCHEMA_CURRENT); 1.74 + sub_generator.next(); 1.75 + yield; 1.76 + 1.77 + this.sub_generator = run_test_3(test_generator, 4); 1.78 + sub_generator.next(); 1.79 + yield; 1.80 + 1.81 + this.sub_generator = run_test_3(test_generator, 3); 1.82 + sub_generator.next(); 1.83 + yield; 1.84 + 1.85 + this.sub_generator = run_test_4_exists(test_generator, 1, 1.86 + "ALTER TABLE moz_cookies ADD lastAccessed INTEGER"); 1.87 + sub_generator.next(); 1.88 + yield; 1.89 + 1.90 + this.sub_generator = run_test_4_exists(test_generator, 2, 1.91 + "ALTER TABLE moz_cookies ADD baseDomain TEXT"); 1.92 + sub_generator.next(); 1.93 + yield; 1.94 + 1.95 + this.sub_generator = run_test_4_baseDomain(test_generator); 1.96 + sub_generator.next(); 1.97 + yield; 1.98 + 1.99 + this.sub_generator = run_test_4_exists(test_generator, 3, 1.100 + "ALTER TABLE moz_cookies ADD creationTime INTEGER"); 1.101 + sub_generator.next(); 1.102 + yield; 1.103 + 1.104 + this.sub_generator = run_test_4_exists(test_generator, 3, 1.105 + "CREATE UNIQUE INDEX moz_uniqueid ON moz_cookies (name, host, path)"); 1.106 + sub_generator.next(); 1.107 + yield; 1.108 + 1.109 + finish_test(); 1.110 + return; 1.111 +} 1.112 + 1.113 +const garbage = "hello thar!"; 1.114 + 1.115 +function create_garbage_file(file) 1.116 +{ 1.117 + // Create an empty database file. 1.118 + file.create(Ci.nsIFile.NORMAL_FILE_TYPE, -1); 1.119 + do_check_true(file.exists()); 1.120 + do_check_eq(file.fileSize, 0); 1.121 + 1.122 + // Write some garbage to it. 1.123 + let ostream = Cc["@mozilla.org/network/file-output-stream;1"]. 1.124 + createInstance(Ci.nsIFileOutputStream); 1.125 + ostream.init(file, -1, -1, 0); 1.126 + ostream.write(garbage, garbage.length); 1.127 + ostream.flush(); 1.128 + ostream.close(); 1.129 + 1.130 + file = file.clone(); // Windows maintains a stat cache. It's lame. 1.131 + do_check_eq(file.fileSize, garbage.length); 1.132 +} 1.133 + 1.134 +function check_garbage_file(file) 1.135 +{ 1.136 + do_check_true(file.exists()); 1.137 + do_check_eq(file.fileSize, garbage.length); 1.138 + file.remove(false); 1.139 + do_check_false(file.exists()); 1.140 +} 1.141 + 1.142 +function run_test_1(generator) 1.143 +{ 1.144 + // Create a garbage database file. 1.145 + create_garbage_file(cookieFile); 1.146 + 1.147 + // Load the profile and populate it. 1.148 + let uri = NetUtil.newURI("http://foo.com/"); 1.149 + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); 1.150 + 1.151 + // Fake a profile change. 1.152 + do_close_profile(sub_generator); 1.153 + yield; 1.154 + do_load_profile(); 1.155 + 1.156 + // Check that the new database contains the cookie, and the old file was 1.157 + // renamed. 1.158 + do_check_eq(do_count_cookies(), 1); 1.159 + check_garbage_file(backupFile); 1.160 + 1.161 + // Close the profile. 1.162 + do_close_profile(sub_generator); 1.163 + yield; 1.164 + 1.165 + // Clean up. 1.166 + cookieFile.remove(false); 1.167 + do_check_false(cookieFile.exists()); 1.168 + do_run_generator(generator); 1.169 +} 1.170 + 1.171 +function run_test_2(generator) 1.172 +{ 1.173 + // Load the profile and populate it. 1.174 + do_load_profile(); 1.175 + let uri = NetUtil.newURI("http://foo.com/"); 1.176 + Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null); 1.177 + 1.178 + // Fake a profile change. 1.179 + do_close_profile(sub_generator); 1.180 + yield; 1.181 + 1.182 + // Drop the table. 1.183 + let db = Services.storage.openDatabase(cookieFile); 1.184 + db.executeSimpleSQL("DROP TABLE moz_cookies"); 1.185 + db.close(); 1.186 + 1.187 + // Load the profile and check that the table is recreated in-place. 1.188 + do_load_profile(); 1.189 + do_check_eq(do_count_cookies(), 0); 1.190 + do_check_false(backupFile.exists()); 1.191 + 1.192 + // Close the profile. 1.193 + do_close_profile(sub_generator); 1.194 + yield; 1.195 + 1.196 + // Clean up. 1.197 + cookieFile.remove(false); 1.198 + do_check_false(cookieFile.exists()); 1.199 + do_run_generator(generator); 1.200 +} 1.201 + 1.202 +function run_test_3(generator, schema) 1.203 +{ 1.204 + // Manually create a schema 2 database, populate it, and set the schema 1.205 + // version to the desired number. 1.206 + let schema2db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); 1.207 + schema2db.insertCookie(cookie); 1.208 + schema2db.db.schemaVersion = schema; 1.209 + schema2db.close(); 1.210 + 1.211 + // Load the profile and check that the column existence test fails. 1.212 + do_load_profile(); 1.213 + do_check_eq(do_count_cookies(), 0); 1.214 + 1.215 + // Close the profile. 1.216 + do_close_profile(sub_generator); 1.217 + yield; 1.218 + 1.219 + // Check that the schema version has been reset. 1.220 + let db = Services.storage.openDatabase(cookieFile); 1.221 + do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); 1.222 + db.close(); 1.223 + 1.224 + // Clean up. 1.225 + cookieFile.remove(false); 1.226 + do_check_false(cookieFile.exists()); 1.227 + do_run_generator(generator); 1.228 +} 1.229 + 1.230 +function run_test_4_exists(generator, schema, stmt) 1.231 +{ 1.232 + // Manually create a database, populate it, and add the desired column. 1.233 + let db = new CookieDatabaseConnection(do_get_cookie_file(profile), schema); 1.234 + db.insertCookie(cookie); 1.235 + db.db.executeSimpleSQL(stmt); 1.236 + db.close(); 1.237 + 1.238 + // Load the profile and check that migration fails. 1.239 + do_load_profile(); 1.240 + do_check_eq(do_count_cookies(), 0); 1.241 + 1.242 + // Close the profile. 1.243 + do_close_profile(sub_generator); 1.244 + yield; 1.245 + 1.246 + // Check that the schema version has been reset and the backup file exists. 1.247 + db = Services.storage.openDatabase(cookieFile); 1.248 + do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); 1.249 + db.close(); 1.250 + do_check_true(backupFile.exists()); 1.251 + 1.252 + // Clean up. 1.253 + cookieFile.remove(false); 1.254 + backupFile.remove(false); 1.255 + do_check_false(cookieFile.exists()); 1.256 + do_check_false(backupFile.exists()); 1.257 + do_run_generator(generator); 1.258 +} 1.259 + 1.260 +function run_test_4_baseDomain(generator) 1.261 +{ 1.262 + // Manually create a database and populate it with a bad host. 1.263 + let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 2); 1.264 + let badCookie = new Cookie("oh", "hai", ".", "/", this.futureExpiry, this.now, 1.265 + this.now, false, false, false); 1.266 + db.insertCookie(badCookie); 1.267 + db.close(); 1.268 + 1.269 + // Load the profile and check that migration fails. 1.270 + do_load_profile(); 1.271 + do_check_eq(do_count_cookies(), 0); 1.272 + 1.273 + // Close the profile. 1.274 + do_close_profile(sub_generator); 1.275 + yield; 1.276 + 1.277 + // Check that the schema version has been reset and the backup file exists. 1.278 + db = Services.storage.openDatabase(cookieFile); 1.279 + do_check_eq(db.schemaVersion, COOKIE_DATABASE_SCHEMA_CURRENT); 1.280 + db.close(); 1.281 + do_check_true(backupFile.exists()); 1.282 + 1.283 + // Clean up. 1.284 + cookieFile.remove(false); 1.285 + backupFile.remove(false); 1.286 + do_check_false(cookieFile.exists()); 1.287 + do_check_false(backupFile.exists()); 1.288 + do_run_generator(generator); 1.289 +}