extensions/cookie/test/unit/test_cookies_async_failure.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 3
michael@0 4 // Test the various ways opening a cookie database can fail in an asynchronous
michael@0 5 // (i.e. after synchronous initialization) manner, and that the database is
michael@0 6 // renamed and recreated under each circumstance. These circumstances are, in no
michael@0 7 // particular order:
michael@0 8 //
michael@0 9 // 1) A write operation failing after the database has been read in.
michael@0 10 // 2) Asynchronous read failure due to a corrupt database.
michael@0 11 // 3) Synchronous read failure due to a corrupt database, when reading:
michael@0 12 // a) a single base domain;
michael@0 13 // b) the entire database.
michael@0 14 // 4) Asynchronous read failure, followed by another failure during INSERT but
michael@0 15 // before the database closes for rebuilding. (The additional error should be
michael@0 16 // ignored.)
michael@0 17 // 5) Asynchronous read failure, followed by an INSERT failure during rebuild.
michael@0 18 // This should result in an abort of the database rebuild; the partially-
michael@0 19 // built database should be moved to 'cookies.sqlite.bak-rebuild'.
michael@0 20
michael@0 21 let test_generator = do_run_test();
michael@0 22
michael@0 23 function run_test() {
michael@0 24 do_test_pending();
michael@0 25 do_run_generator(test_generator);
michael@0 26 }
michael@0 27
michael@0 28 function finish_test() {
michael@0 29 do_execute_soon(function() {
michael@0 30 test_generator.close();
michael@0 31 do_test_finished();
michael@0 32 });
michael@0 33 }
michael@0 34
michael@0 35 function do_run_test() {
michael@0 36 // Set up a profile.
michael@0 37 this.profile = do_get_profile();
michael@0 38
michael@0 39 // Allow all cookies.
michael@0 40 Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
michael@0 41
michael@0 42 // Get the cookie file and the backup file.
michael@0 43 do_check_false(do_get_cookie_file(profile).exists());
michael@0 44 do_check_false(do_get_backup_file(profile).exists());
michael@0 45
michael@0 46 // Create a cookie object for testing.
michael@0 47 this.now = Date.now() * 1000;
michael@0 48 this.futureExpiry = Math.round(this.now / 1e6 + 1000);
michael@0 49 this.cookie = new Cookie("oh", "hai", "bar.com", "/", this.futureExpiry,
michael@0 50 this.now, this.now, false, false, false);
michael@0 51
michael@0 52 this.sub_generator = run_test_1(test_generator);
michael@0 53 sub_generator.next();
michael@0 54 yield;
michael@0 55
michael@0 56 this.sub_generator = run_test_2(test_generator);
michael@0 57 sub_generator.next();
michael@0 58 yield;
michael@0 59
michael@0 60 this.sub_generator = run_test_3(test_generator);
michael@0 61 sub_generator.next();
michael@0 62 yield;
michael@0 63
michael@0 64 this.sub_generator = run_test_4(test_generator);
michael@0 65 sub_generator.next();
michael@0 66 yield;
michael@0 67
michael@0 68 this.sub_generator = run_test_5(test_generator);
michael@0 69 sub_generator.next();
michael@0 70 yield;
michael@0 71
michael@0 72 finish_test();
michael@0 73 return;
michael@0 74 }
michael@0 75
michael@0 76 function do_get_backup_file(profile)
michael@0 77 {
michael@0 78 let file = profile.clone();
michael@0 79 file.append("cookies.sqlite.bak");
michael@0 80 return file;
michael@0 81 }
michael@0 82
michael@0 83 function do_get_rebuild_backup_file(profile)
michael@0 84 {
michael@0 85 let file = profile.clone();
michael@0 86 file.append("cookies.sqlite.bak-rebuild");
michael@0 87 return file;
michael@0 88 }
michael@0 89
michael@0 90 function do_corrupt_db(file)
michael@0 91 {
michael@0 92 // Sanity check: the database size should be larger than 450k, since we've
michael@0 93 // written about 460k of data. If it's not, let's make it obvious now.
michael@0 94 let size = file.fileSize;
michael@0 95 do_check_true(size > 450e3);
michael@0 96
michael@0 97 // Corrupt the database by writing bad data to the end of the file. We
michael@0 98 // assume that the important metadata -- table structure etc -- is stored
michael@0 99 // elsewhere, and that doing this will not cause synchronous failure when
michael@0 100 // initializing the database connection. This is totally empirical --
michael@0 101 // overwriting between 1k and 100k of live data seems to work. (Note that the
michael@0 102 // database file will be larger than the actual content requires, since the
michael@0 103 // cookie service uses a large growth increment. So we calculate the offset
michael@0 104 // based on the expected size of the content, not just the file size.)
michael@0 105 let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
michael@0 106 createInstance(Ci.nsIFileOutputStream);
michael@0 107 ostream.init(file, 2, -1, 0);
michael@0 108 let sstream = ostream.QueryInterface(Ci.nsISeekableStream);
michael@0 109 let n = size - 450e3 + 20e3;
michael@0 110 sstream.seek(Ci.nsISeekableStream.NS_SEEK_SET, size - n);
michael@0 111 for (let i = 0; i < n; ++i) {
michael@0 112 ostream.write("a", 1);
michael@0 113 }
michael@0 114 ostream.flush();
michael@0 115 ostream.close();
michael@0 116
michael@0 117 do_check_eq(file.clone().fileSize, size);
michael@0 118 return size;
michael@0 119 }
michael@0 120
michael@0 121 function run_test_1(generator)
michael@0 122 {
michael@0 123 // Load the profile and populate it.
michael@0 124 let uri = NetUtil.newURI("http://foo.com/");
michael@0 125 Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
michael@0 126
michael@0 127 // Close the profile.
michael@0 128 do_close_profile(sub_generator);
michael@0 129 yield;
michael@0 130
michael@0 131 // Open a database connection now, before we load the profile and begin
michael@0 132 // asynchronous write operations. In order to tell when the async delete
michael@0 133 // statement has completed, we do something tricky: open a schema 2 connection
michael@0 134 // and add a cookie with null baseDomain. We can then wait until we see it
michael@0 135 // deleted in the new database.
michael@0 136 let db2 = new CookieDatabaseConnection(do_get_cookie_file(profile), 2);
michael@0 137 db2.db.executeSimpleSQL("INSERT INTO moz_cookies (baseDomain) VALUES (NULL)");
michael@0 138 db2.close();
michael@0 139 let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 4);
michael@0 140 do_check_eq(do_count_cookies_in_db(db.db), 2);
michael@0 141
michael@0 142 // Load the profile, and wait for async read completion...
michael@0 143 do_load_profile(sub_generator);
michael@0 144 yield;
michael@0 145
michael@0 146 // ... and the DELETE statement to finish.
michael@0 147 while (do_count_cookies_in_db(db.db) == 2) {
michael@0 148 do_execute_soon(function() {
michael@0 149 do_run_generator(sub_generator);
michael@0 150 });
michael@0 151 yield;
michael@0 152 }
michael@0 153 do_check_eq(do_count_cookies_in_db(db.db), 1);
michael@0 154
michael@0 155 // Insert a row.
michael@0 156 db.insertCookie(cookie);
michael@0 157 db.close();
michael@0 158
michael@0 159 // Attempt to insert a cookie with the same (name, host, path) triplet.
michael@0 160 Services.cookiemgr.add(cookie.host, cookie.path, cookie.name, "hallo",
michael@0 161 cookie.isSecure, cookie.isHttpOnly, cookie.isSession, cookie.expiry);
michael@0 162
michael@0 163 // Check that the cookie service accepted the new cookie.
michael@0 164 do_check_eq(Services.cookiemgr.countCookiesFromHost(cookie.host), 1);
michael@0 165
michael@0 166 // Wait for the cookie service to rename the old database and rebuild.
michael@0 167 new _observer(sub_generator, "cookie-db-rebuilding");
michael@0 168 yield;
michael@0 169 do_execute_soon(function() { do_run_generator(sub_generator); });
michael@0 170 yield;
michael@0 171
michael@0 172 // At this point, the cookies should still be in memory.
michael@0 173 do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 1);
michael@0 174 do_check_eq(Services.cookiemgr.countCookiesFromHost(cookie.host), 1);
michael@0 175 do_check_eq(do_count_cookies(), 2);
michael@0 176
michael@0 177 // Close the profile.
michael@0 178 do_close_profile(sub_generator);
michael@0 179 yield;
michael@0 180
michael@0 181 // Check that the original database was renamed, and that it contains the
michael@0 182 // original cookie.
michael@0 183 do_check_true(do_get_backup_file(profile).exists());
michael@0 184 let backupdb = Services.storage.openDatabase(do_get_backup_file(profile));
michael@0 185 do_check_eq(do_count_cookies_in_db(backupdb, "foo.com"), 1);
michael@0 186 backupdb.close();
michael@0 187
michael@0 188 // Load the profile, and check that it contains the new cookie.
michael@0 189 do_load_profile();
michael@0 190
michael@0 191 do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 1);
michael@0 192 let enumerator = Services.cookiemgr.getCookiesFromHost(cookie.host);
michael@0 193 do_check_true(enumerator.hasMoreElements());
michael@0 194 let dbcookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
michael@0 195 do_check_eq(dbcookie.value, "hallo");
michael@0 196 do_check_false(enumerator.hasMoreElements());
michael@0 197
michael@0 198 // Close the profile.
michael@0 199 do_close_profile(sub_generator);
michael@0 200 yield;
michael@0 201
michael@0 202 // Clean up.
michael@0 203 do_get_cookie_file(profile).remove(false);
michael@0 204 do_get_backup_file(profile).remove(false);
michael@0 205 do_check_false(do_get_cookie_file(profile).exists());
michael@0 206 do_check_false(do_get_backup_file(profile).exists());
michael@0 207 do_run_generator(generator);
michael@0 208 }
michael@0 209
michael@0 210 function run_test_2(generator)
michael@0 211 {
michael@0 212 // Load the profile and populate it.
michael@0 213 do_load_profile();
michael@0 214 for (let i = 0; i < 3000; ++i) {
michael@0 215 let uri = NetUtil.newURI("http://" + i + ".com/");
michael@0 216 Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
michael@0 217 }
michael@0 218
michael@0 219 // Close the profile.
michael@0 220 do_close_profile(sub_generator);
michael@0 221 yield;
michael@0 222
michael@0 223 // Corrupt the database file.
michael@0 224 let size = do_corrupt_db(do_get_cookie_file(profile));
michael@0 225
michael@0 226 // Load the profile.
michael@0 227 do_load_profile();
michael@0 228
michael@0 229 // At this point, the database connection should be open. Ensure that it
michael@0 230 // succeeded.
michael@0 231 do_check_false(do_get_backup_file(profile).exists());
michael@0 232
michael@0 233 // Synchronously read in the first cookie. This will cause it to go into the
michael@0 234 // cookie table, whereupon it will be written out during database rebuild.
michael@0 235 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 236
michael@0 237 // Wait for the asynchronous read to choke, at which point the backup file
michael@0 238 // will be created and the database rebuilt.
michael@0 239 new _observer(sub_generator, "cookie-db-rebuilding");
michael@0 240 yield;
michael@0 241 do_execute_soon(function() { do_run_generator(sub_generator); });
michael@0 242 yield;
michael@0 243
michael@0 244 // At this point, the cookies should still be in memory.
michael@0 245 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 246 do_check_eq(do_count_cookies(), 1);
michael@0 247
michael@0 248 // Close the profile.
michael@0 249 do_close_profile(sub_generator);
michael@0 250 yield;
michael@0 251
michael@0 252 // Check that the original database was renamed.
michael@0 253 do_check_true(do_get_backup_file(profile).exists());
michael@0 254 do_check_eq(do_get_backup_file(profile).fileSize, size);
michael@0 255 let db = Services.storage.openDatabase(do_get_cookie_file(profile));
michael@0 256 do_check_eq(do_count_cookies_in_db(db, "0.com"), 1);
michael@0 257 db.close();
michael@0 258
michael@0 259 // Load the profile, and check that it contains the new cookie.
michael@0 260 do_load_profile();
michael@0 261 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 262 do_check_eq(do_count_cookies(), 1);
michael@0 263
michael@0 264 // Close the profile.
michael@0 265 do_close_profile(sub_generator);
michael@0 266 yield;
michael@0 267
michael@0 268 // Clean up.
michael@0 269 do_get_cookie_file(profile).remove(false);
michael@0 270 do_get_backup_file(profile).remove(false);
michael@0 271 do_check_false(do_get_cookie_file(profile).exists());
michael@0 272 do_check_false(do_get_backup_file(profile).exists());
michael@0 273 do_run_generator(generator);
michael@0 274 }
michael@0 275
michael@0 276 function run_test_3(generator)
michael@0 277 {
michael@0 278 // Set the maximum cookies per base domain limit to a large value, so that
michael@0 279 // corrupting the database is easier.
michael@0 280 Services.prefs.setIntPref("network.cookie.maxPerHost", 3000);
michael@0 281
michael@0 282 // Load the profile and populate it.
michael@0 283 do_load_profile();
michael@0 284 for (let i = 0; i < 10; ++i) {
michael@0 285 let uri = NetUtil.newURI("http://hither.com/");
michael@0 286 Services.cookies.setCookieString(uri, null, "oh" + i + "=hai; max-age=1000",
michael@0 287 null);
michael@0 288 }
michael@0 289 for (let i = 10; i < 3000; ++i) {
michael@0 290 let uri = NetUtil.newURI("http://haithur.com/");
michael@0 291 Services.cookies.setCookieString(uri, null, "oh" + i + "=hai; max-age=1000",
michael@0 292 null);
michael@0 293 }
michael@0 294
michael@0 295 // Close the profile.
michael@0 296 do_close_profile(sub_generator);
michael@0 297 yield;
michael@0 298
michael@0 299 // Corrupt the database file.
michael@0 300 let size = do_corrupt_db(do_get_cookie_file(profile));
michael@0 301
michael@0 302 // Load the profile.
michael@0 303 do_load_profile();
michael@0 304
michael@0 305 // At this point, the database connection should be open. Ensure that it
michael@0 306 // succeeded.
michael@0 307 do_check_false(do_get_backup_file(profile).exists());
michael@0 308
michael@0 309 // Synchronously read in the cookies for our two domains. The first should
michael@0 310 // succeed, but the second should fail midway through, resulting in none of
michael@0 311 // those cookies being present.
michael@0 312 do_check_eq(Services.cookiemgr.countCookiesFromHost("hither.com"), 10);
michael@0 313 do_check_eq(Services.cookiemgr.countCookiesFromHost("haithur.com"), 0);
michael@0 314
michael@0 315 // Wait for the backup file to be created and the database rebuilt.
michael@0 316 do_check_false(do_get_backup_file(profile).exists());
michael@0 317 new _observer(sub_generator, "cookie-db-rebuilding");
michael@0 318 yield;
michael@0 319 do_execute_soon(function() { do_run_generator(sub_generator); });
michael@0 320 yield;
michael@0 321
michael@0 322 // Close the profile.
michael@0 323 do_close_profile(sub_generator);
michael@0 324 yield;
michael@0 325 let db = Services.storage.openDatabase(do_get_cookie_file(profile));
michael@0 326 do_check_eq(do_count_cookies_in_db(db, "hither.com"), 10);
michael@0 327 do_check_eq(do_count_cookies_in_db(db), 10);
michael@0 328 db.close();
michael@0 329
michael@0 330 // Check that the original database was renamed.
michael@0 331 do_check_true(do_get_backup_file(profile).exists());
michael@0 332 do_check_eq(do_get_backup_file(profile).fileSize, size);
michael@0 333
michael@0 334 // Rename it back, and try loading the entire database synchronously.
michael@0 335 do_get_backup_file(profile).moveTo(null, "cookies.sqlite");
michael@0 336 do_load_profile();
michael@0 337
michael@0 338 // At this point, the database connection should be open. Ensure that it
michael@0 339 // succeeded.
michael@0 340 do_check_false(do_get_backup_file(profile).exists());
michael@0 341
michael@0 342 // Synchronously read in everything.
michael@0 343 do_check_eq(do_count_cookies(), 0);
michael@0 344
michael@0 345 // Wait for the backup file to be created and the database rebuilt.
michael@0 346 do_check_false(do_get_backup_file(profile).exists());
michael@0 347 new _observer(sub_generator, "cookie-db-rebuilding");
michael@0 348 yield;
michael@0 349 do_execute_soon(function() { do_run_generator(sub_generator); });
michael@0 350 yield;
michael@0 351
michael@0 352 // Close the profile.
michael@0 353 do_close_profile(sub_generator);
michael@0 354 yield;
michael@0 355 let db = Services.storage.openDatabase(do_get_cookie_file(profile));
michael@0 356 do_check_eq(do_count_cookies_in_db(db), 0);
michael@0 357 db.close();
michael@0 358
michael@0 359 // Check that the original database was renamed.
michael@0 360 do_check_true(do_get_backup_file(profile).exists());
michael@0 361 do_check_eq(do_get_backup_file(profile).fileSize, size);
michael@0 362
michael@0 363 // Clean up.
michael@0 364 do_get_cookie_file(profile).remove(false);
michael@0 365 do_get_backup_file(profile).remove(false);
michael@0 366 do_check_false(do_get_cookie_file(profile).exists());
michael@0 367 do_check_false(do_get_backup_file(profile).exists());
michael@0 368 do_run_generator(generator);
michael@0 369 }
michael@0 370
michael@0 371 function run_test_4(generator)
michael@0 372 {
michael@0 373 // Load the profile and populate it.
michael@0 374 do_load_profile();
michael@0 375 for (let i = 0; i < 3000; ++i) {
michael@0 376 let uri = NetUtil.newURI("http://" + i + ".com/");
michael@0 377 Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
michael@0 378 }
michael@0 379
michael@0 380 // Close the profile.
michael@0 381 do_close_profile(sub_generator);
michael@0 382 yield;
michael@0 383
michael@0 384 // Corrupt the database file.
michael@0 385 let size = do_corrupt_db(do_get_cookie_file(profile));
michael@0 386
michael@0 387 // Load the profile.
michael@0 388 do_load_profile();
michael@0 389
michael@0 390 // At this point, the database connection should be open. Ensure that it
michael@0 391 // succeeded.
michael@0 392 do_check_false(do_get_backup_file(profile).exists());
michael@0 393
michael@0 394 // Synchronously read in the first cookie. This will cause it to go into the
michael@0 395 // cookie table, whereupon it will be written out during database rebuild.
michael@0 396 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 397
michael@0 398 // Queue up an INSERT for the same base domain. This should also go into
michael@0 399 // memory and be written out during database rebuild.
michael@0 400 let uri = NetUtil.newURI("http://0.com/");
michael@0 401 Services.cookies.setCookieString(uri, null, "oh2=hai; max-age=1000", null);
michael@0 402
michael@0 403 // Wait for the asynchronous read to choke and the insert to fail shortly
michael@0 404 // thereafter, at which point the backup file will be created and the database
michael@0 405 // rebuilt.
michael@0 406 new _observer(sub_generator, "cookie-db-rebuilding");
michael@0 407 yield;
michael@0 408 do_execute_soon(function() { do_run_generator(sub_generator); });
michael@0 409 yield;
michael@0 410
michael@0 411 // Close the profile.
michael@0 412 do_close_profile(sub_generator);
michael@0 413 yield;
michael@0 414
michael@0 415 // Check that the original database was renamed.
michael@0 416 do_check_true(do_get_backup_file(profile).exists());
michael@0 417 do_check_eq(do_get_backup_file(profile).fileSize, size);
michael@0 418 let db = Services.storage.openDatabase(do_get_cookie_file(profile));
michael@0 419 do_check_eq(do_count_cookies_in_db(db, "0.com"), 2);
michael@0 420 db.close();
michael@0 421
michael@0 422 // Load the profile, and check that it contains the new cookie.
michael@0 423 do_load_profile();
michael@0 424 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 2);
michael@0 425 do_check_eq(do_count_cookies(), 2);
michael@0 426
michael@0 427 // Close the profile.
michael@0 428 do_close_profile(sub_generator);
michael@0 429 yield;
michael@0 430
michael@0 431 // Clean up.
michael@0 432 do_get_cookie_file(profile).remove(false);
michael@0 433 do_get_backup_file(profile).remove(false);
michael@0 434 do_check_false(do_get_cookie_file(profile).exists());
michael@0 435 do_check_false(do_get_backup_file(profile).exists());
michael@0 436 do_run_generator(generator);
michael@0 437 }
michael@0 438
michael@0 439 function run_test_4(generator)
michael@0 440 {
michael@0 441 // Load the profile and populate it.
michael@0 442 do_load_profile();
michael@0 443 for (let i = 0; i < 3000; ++i) {
michael@0 444 let uri = NetUtil.newURI("http://" + i + ".com/");
michael@0 445 Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
michael@0 446 }
michael@0 447
michael@0 448 // Close the profile.
michael@0 449 do_close_profile(sub_generator);
michael@0 450 yield;
michael@0 451
michael@0 452 // Corrupt the database file.
michael@0 453 let size = do_corrupt_db(do_get_cookie_file(profile));
michael@0 454
michael@0 455 // Load the profile.
michael@0 456 do_load_profile();
michael@0 457
michael@0 458 // At this point, the database connection should be open. Ensure that it
michael@0 459 // succeeded.
michael@0 460 do_check_false(do_get_backup_file(profile).exists());
michael@0 461
michael@0 462 // Synchronously read in the first cookie. This will cause it to go into the
michael@0 463 // cookie table, whereupon it will be written out during database rebuild.
michael@0 464 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 465
michael@0 466 // Queue up an INSERT for the same base domain. This should also go into
michael@0 467 // memory and be written out during database rebuild.
michael@0 468 let uri = NetUtil.newURI("http://0.com/");
michael@0 469 Services.cookies.setCookieString(uri, null, "oh2=hai; max-age=1000", null);
michael@0 470
michael@0 471 // Wait for the asynchronous read to choke and the insert to fail shortly
michael@0 472 // thereafter, at which point the backup file will be created and the database
michael@0 473 // rebuilt.
michael@0 474 new _observer(sub_generator, "cookie-db-rebuilding");
michael@0 475 yield;
michael@0 476 do_execute_soon(function() { do_run_generator(sub_generator); });
michael@0 477 yield;
michael@0 478
michael@0 479 // At this point, the cookies should still be in memory.
michael@0 480 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 2);
michael@0 481 do_check_eq(do_count_cookies(), 2);
michael@0 482
michael@0 483 // Close the profile.
michael@0 484 do_close_profile(sub_generator);
michael@0 485 yield;
michael@0 486
michael@0 487 // Check that the original database was renamed.
michael@0 488 do_check_true(do_get_backup_file(profile).exists());
michael@0 489 do_check_eq(do_get_backup_file(profile).fileSize, size);
michael@0 490 let db = Services.storage.openDatabase(do_get_cookie_file(profile));
michael@0 491 do_check_eq(do_count_cookies_in_db(db, "0.com"), 2);
michael@0 492 db.close();
michael@0 493
michael@0 494 // Load the profile, and check that it contains the new cookie.
michael@0 495 do_load_profile();
michael@0 496 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 2);
michael@0 497 do_check_eq(do_count_cookies(), 2);
michael@0 498
michael@0 499 // Close the profile.
michael@0 500 do_close_profile(sub_generator);
michael@0 501 yield;
michael@0 502
michael@0 503 // Clean up.
michael@0 504 do_get_cookie_file(profile).remove(false);
michael@0 505 do_get_backup_file(profile).remove(false);
michael@0 506 do_check_false(do_get_cookie_file(profile).exists());
michael@0 507 do_check_false(do_get_backup_file(profile).exists());
michael@0 508 do_run_generator(generator);
michael@0 509 }
michael@0 510
michael@0 511 function run_test_5(generator)
michael@0 512 {
michael@0 513 // Load the profile and populate it.
michael@0 514 do_load_profile();
michael@0 515 let uri = NetUtil.newURI("http://bar.com/");
michael@0 516 Services.cookies.setCookieString(uri, null, "oh=hai; path=/; max-age=1000",
michael@0 517 null);
michael@0 518 for (let i = 0; i < 3000; ++i) {
michael@0 519 let uri = NetUtil.newURI("http://" + i + ".com/");
michael@0 520 Services.cookies.setCookieString(uri, null, "oh=hai; max-age=1000", null);
michael@0 521 }
michael@0 522
michael@0 523 // Close the profile.
michael@0 524 do_close_profile(sub_generator);
michael@0 525 yield;
michael@0 526
michael@0 527 // Corrupt the database file.
michael@0 528 let size = do_corrupt_db(do_get_cookie_file(profile));
michael@0 529
michael@0 530 // Load the profile.
michael@0 531 do_load_profile();
michael@0 532
michael@0 533 // At this point, the database connection should be open. Ensure that it
michael@0 534 // succeeded.
michael@0 535 do_check_false(do_get_backup_file(profile).exists());
michael@0 536
michael@0 537 // Synchronously read in the first two cookies. This will cause them to go
michael@0 538 // into the cookie table, whereupon it will be written out during database
michael@0 539 // rebuild.
michael@0 540 do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 1);
michael@0 541 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 542
michael@0 543 // Wait for the asynchronous read to choke, at which point the backup file
michael@0 544 // will be created and a new connection opened.
michael@0 545 new _observer(sub_generator, "cookie-db-rebuilding");
michael@0 546 yield;
michael@0 547
michael@0 548 // At this point, the cookies should still be in memory. (Note that these
michael@0 549 // calls are re-entrant into the cookie service, but it's OK!)
michael@0 550 do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 1);
michael@0 551 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 552 do_check_eq(do_count_cookies(), 2);
michael@0 553 do_check_true(do_get_backup_file(profile).exists());
michael@0 554 do_check_eq(do_get_backup_file(profile).fileSize, size);
michael@0 555 do_check_false(do_get_rebuild_backup_file(profile).exists());
michael@0 556
michael@0 557 // Open a database connection, and write a row that will trigger a constraint
michael@0 558 // violation.
michael@0 559 let db = new CookieDatabaseConnection(do_get_cookie_file(profile), 4);
michael@0 560 db.insertCookie(cookie);
michael@0 561 do_check_eq(do_count_cookies_in_db(db.db, "bar.com"), 1);
michael@0 562 do_check_eq(do_count_cookies_in_db(db.db), 1);
michael@0 563 db.close();
michael@0 564
michael@0 565 // Wait for the rebuild to bail and the database to be closed.
michael@0 566 new _observer(sub_generator, "cookie-db-closed");
michael@0 567 yield;
michael@0 568
michael@0 569 // Check that the original backup and the database itself are gone.
michael@0 570 do_check_true(do_get_rebuild_backup_file(profile).exists());
michael@0 571 do_check_true(do_get_backup_file(profile).exists());
michael@0 572 do_check_eq(do_get_backup_file(profile).fileSize, size);
michael@0 573 do_check_false(do_get_cookie_file(profile).exists());
michael@0 574
michael@0 575 // Check that the rebuild backup has the original bar.com cookie, and possibly
michael@0 576 // a 0.com cookie depending on whether it got written out first or second.
michael@0 577 db = new CookieDatabaseConnection(do_get_rebuild_backup_file(profile), 4);
michael@0 578 do_check_eq(do_count_cookies_in_db(db.db, "bar.com"), 1);
michael@0 579 let count = do_count_cookies_in_db(db.db);
michael@0 580 do_check_true(count == 1 ||
michael@0 581 count == 2 && do_count_cookies_in_db(db.db, "0.com") == 1);
michael@0 582 db.close();
michael@0 583
michael@0 584 do_check_eq(Services.cookiemgr.countCookiesFromHost("bar.com"), 1);
michael@0 585 do_check_eq(Services.cookiemgr.countCookiesFromHost("0.com"), 1);
michael@0 586 do_check_eq(do_count_cookies(), 2);
michael@0 587
michael@0 588 // Close the profile. We do not need to wait for completion, because the
michael@0 589 // database has already been closed.
michael@0 590 do_close_profile();
michael@0 591
michael@0 592 // Clean up.
michael@0 593 do_get_backup_file(profile).remove(false);
michael@0 594 do_get_rebuild_backup_file(profile).remove(false);
michael@0 595 do_check_false(do_get_cookie_file(profile).exists());
michael@0 596 do_check_false(do_get_backup_file(profile).exists());
michael@0 597 do_check_false(do_get_rebuild_backup_file(profile).exists());
michael@0 598 do_run_generator(generator);
michael@0 599 }
michael@0 600

mercurial