Commit 6845def2 authored by Jan Varga's avatar Jan Varga
Browse files

Bug 1182987 - Part 4: Add a test for QuotaExceededError recovery and the new...

Bug 1182987 - Part 4: Add a test for QuotaExceededError recovery and the new "cleanup" transaction type; r=baku
parent e5780917
Loading
Loading
Loading
Loading
+153 −0
Original line number Diff line number Diff line
/**
 * Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

var disableWorkerTest = "Need a way to set temporary prefs from a worker";

var testGenerator = testSteps();

function testSteps()
{
  const spec = "http://foo.com";
  const name =
    this.window ? window.location.pathname : "test_quotaExceeded_recovery";
  const objectStoreName = "foo";

  // We want 32 MB database file, but there's the group limit so we need to
  // multiply by 5.
  const tempStorageLimitKB = 32 * 1024 * 5;

  // Store in 1 MB chunks.
  const dataSize = 1024 * 1024;

  for (let blobs of [false, true]) {
    setTemporaryStorageLimit(tempStorageLimitKB);

    clearAllDatabases(continueToNextStepSync);
    yield undefined;

    info("Opening database");

    let request = indexedDB.openForPrincipal(getPrincipal(spec), name);
    request.onerror = errorHandler;
    request.onupgradeneeded = grabEventAndContinueHandler;;
    request.onsuccess = unexpectedSuccessHandler;

    yield undefined;

    // upgradeneeded
    request.onupgradeneeded = unexpectedSuccessHandler;
    request.onsuccess = grabEventAndContinueHandler;

    info("Creating objectStore");

    request.result.createObjectStore(objectStoreName);

    yield undefined;

    // success
    let db = request.result;
    db.onerror = errorHandler;

    ok(true, "Adding data until quota is reached");

    let obj = {
      name: "foo"
    }

    if (!blobs) {
      obj.data = getRandomView(dataSize);
    }

    let i = 1;
    let j = 1;
    while (true) {
      if (blobs) {
        obj.data = getBlob(getView(dataSize));
      }

      let trans = db.transaction(objectStoreName, "readwrite");
      request = trans.objectStore(objectStoreName).add(obj, i);
      request.onerror = function(event)
      {
        event.stopPropagation();
      }

      trans.oncomplete = function(event) {
        i++;
        j++;
        testGenerator.send(true);
      }
      trans.onabort = function(event) {
        is(trans.error.name, "QuotaExceededError", "Reached quota limit");
        testGenerator.send(false);
      }

      let shouldContinue = yield undefined;
      if (shouldContinue) {
        ok(true, "Got complete event");
      } else {
        ok(true, "Got abort event");

        if (j==1) {
          break;
        } else {
          j = 1;

          trans = db.transaction(objectStoreName, "cleanup");
          trans.onabort = unexpectedSuccessHandler;;
          trans.oncomplete = grabEventAndContinueHandler;

          yield undefined;
        }
      }
    }

    info("Reopening database");

    db.close();

    request = indexedDB.openForPrincipal(getPrincipal(spec), name);
    request.onerror = errorHandler;
    request.onsuccess = grabEventAndContinueHandler;

    yield undefined;

    db = request.result;
    db.onerror = errorHandler;

    info("Deleting some data")

    let trans = db.transaction(objectStoreName, "cleanup");
    trans.objectStore(objectStoreName).delete(1);

    trans.onabort = unexpectedSuccessHandler;;
    trans.oncomplete = grabEventAndContinueHandler;

    yield undefined;

    info("Adding data again")

    trans = db.transaction(objectStoreName, "readwrite");
    trans.objectStore(objectStoreName).add(obj, 1);

    trans.onabort = unexpectedSuccessHandler;
    trans.oncomplete = grabEventAndContinueHandler;

    yield undefined;

    info("Deleting database");

    db.close();

    request = indexedDB.deleteForPrincipal(getPrincipal(spec), name);
    request.onerror = errorHandler;
    request.onsuccess = grabEventAndContinueHandler;

    yield undefined;
  }

  finishTest();
  yield undefined;
}
+4 −24
Original line number Diff line number Diff line
@@ -15,34 +15,14 @@ function testSteps()
  const tempStorageLimitKB = 1024;
  const checkpointSleepTimeSec = 5;

  function setLimit(limit) {
    const pref = "dom.quotaManager.temporaryStorage.fixedLimit";
    if (limit) {
      info("Setting temporary storage limit to " + limit);
      SpecialPowers.setIntPref(pref, limit);
    } else {
      info("Removing temporary storage limit");
      SpecialPowers.clearUserPref(pref);
    }
  }

  function getSpec(index) {
    return "http://foo" + index + ".com";
  }

  function getPrincipal(url) {
    let uri = Cc["@mozilla.org/network/io-service;1"]
                .getService(Ci.nsIIOService)
                .newURI(url, null, null);
    let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
                .getService(Ci.nsIScriptSecurityManager);
    return ssm.createCodebasePrincipal(uri, {});
  }

  for (let temporary of [true, false]) {
    info("Testing '" + (temporary ? "temporary" : "default") + "' storage");

    setLimit(tempStorageLimitKB);
    setTemporaryStorageLimit(tempStorageLimitKB);

    clearAllDatabases(continueToNextStepSync);
    yield undefined;
@@ -165,7 +145,7 @@ function testSteps()
    db.close();
    db = null;

    setLimit(tempStorageLimitKB * 2);
    setTemporaryStorageLimit(tempStorageLimitKB * 2);

    resetAllDatabases(continueToNextStepSync);
    yield undefined;
@@ -197,7 +177,7 @@ function testSteps()
    info("Stage 3 - " +
         "Cutting storage limit in half to force deletion of some databases");

    setLimit(tempStorageLimitKB / 2);
    setTemporaryStorageLimit(tempStorageLimitKB / 2);

    resetAllDatabases(continueToNextStepSync);
    yield undefined;
@@ -220,7 +200,7 @@ function testSteps()
    db.close();
    db = null;

    setLimit(tempStorageLimitKB * 2);
    setTemporaryStorageLimit(tempStorageLimitKB * 2);

    resetAllDatabases(continueToNextStepSync);
    yield undefined;
+39 −0
Original line number Diff line number Diff line
@@ -331,6 +331,23 @@ function installPackagedProfile(packageName)
  zipReader.close();
}

function getView(size)
{
  let buffer = new ArrayBuffer(size);
  let view = new Uint8Array(buffer);
  is(buffer.byteLength, size, "Correct byte length");
  return view;
}

function getRandomView(size)
{
  let view = getView(size);
  for (let i = 0; i < size; i++) {
    view[i] = parseInt(Math.random() * 255)
  }
  return view;
}

function getBlob(str)
{
  return new Blob([str], {type: "type/text"});
@@ -418,6 +435,28 @@ function verifyMutableFile(mutableFile1, file2)
  });
}

function setTemporaryStorageLimit(limit)
{
  const pref = "dom.quotaManager.temporaryStorage.fixedLimit";
  if (limit) {
    info("Setting temporary storage limit to " + limit);
    SpecialPowers.setIntPref(pref, limit);
  } else {
    info("Removing temporary storage limit");
    SpecialPowers.clearUserPref(pref);
  }
}

function getPrincipal(url)
{
  let uri = Cc["@mozilla.org/network/io-service;1"]
              .getService(Ci.nsIIOService)
              .newURI(url, null, null);
  let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"]
              .getService(Ci.nsIScriptSecurityManager);
  return ssm.createCodebasePrincipal(uri, {});
}

var SpecialPowers = {
  isMainProcess: function() {
    return Components.classes["@mozilla.org/xre/app-info;1"]
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ skip-if = true
[test_lowDiskSpace.js]
[test_metadataRestore.js]
[test_mutableFileUpgrade.js]
[test_quotaExceeded_recovery.js]
[test_readwriteflush_disabled.js]
[test_schema18upgrade.js]
[test_schema21upgrade.js]