<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingManifest.sjs">
<head>
<title>Cache update test</title>

<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />

<script class="testbody" type="text/javascript">

/**
 * This test loads manifest and checks presence of all items.
 * Then it modifies the manifest and updates the cache again.
 * Then test presence of items according to the spec and also
 * if the cache associated with the document is still the old
 * one. Then again modifies the manifest, checks items and finally
 * swaps cache for this document, reloads and checks document state.
 */

const NAMESPACE_BYPASS = SpecialPowers.Ci.nsIApplicationCacheNamespace.NAMESPACE_BYPASS;
const NAMESPACE_FALLBACK = SpecialPowers.Ci.nsIApplicationCacheNamespace.NAMESPACE_FALLBACK;

var gStep = 0;
var gGotFrameVersion = 0;
var gCallOnUpdatingFrameLoad = null;

// Helpers

function reloadLocations(frames)
{
  for (frame in frames)
    frames[frame].location.reload();
}

function waitForLocations(frames, doneFunc)
{
  frame = frames.shift();
  if (frame)
    // toString() might cause problems when this test will
    // completely be changed to test IDN behavior.
    OfflineTest.waitForAdd(frame, function()
      {
        waitForLocations(frames, doneFunc);
      }
    );
  else
  {
    doneFunc();
  }
}

function checkFallbackAndWhitelisting(key, fallback, onwhitelist)
{
  // Get matching namespace for the key
  var matchingNamespace = OfflineTest.getActiveCache()
    .getMatchingNamespace(key);

  // If we are not expecting the key is to be on white list or
  // has been assigned a fallback check there is not any matching
  // namespace found and exit
  if (!fallback && !onwhitelist) {
    is(matchingNamespace, null, "No namespace found for "+key);
    return;
  }

  // We expect this entry is on the white list or has a fallback
  // entry assigned, check we found a matching namespace
  ok(matchingNamespace, "We have a namespace for "+key);
  if (!matchingNamespace)
    return;

  // We expect the key be assigned a fallback URI, check the namespace
  // type is of fallback type
  OfflineTest.is(!!(matchingNamespace.itemType & NAMESPACE_FALLBACK), !!fallback,
    (fallback ? "Namespace type is fallback for " : "Namespace type is not fallback for ")+key);

  // We expect the key be assigned a fallback URI, check the URI is
  // equal to expected one
  OfflineTest.is(matchingNamespace.data, fallback,
    (fallback ? "Expected correct fallback for " : "No fallback for ")+key);

  // We expect the key be on the white list, check the namespace type
  // is of bypass type
  OfflineTest.is(!!(matchingNamespace.itemType & NAMESPACE_BYPASS), onwhitelist,
    (onwhitelist ? "On white list " : "Not on white list ")+key);
}

// Events

function frameLoad(version)
{
  gGotFrameVersion = version;
  if (gCallOnUpdatingFrameLoad)
  {
    var call = gCallOnUpdatingFrameLoad;
    gCallOnUpdatingFrameLoad = null;
    SimpleTest.executeSoon(OfflineTest.priv(call));
  }
}

function whitelistOnLoad(version)
{
  // Whitelisting is not tested by this test...
}


// Start of the test function chain
// ================================

function manifestCached()
{
  OfflineTest.is(gStep, 0, "Got manifestCached in step 0, gStep=" + gStep);

  reloadLocations([fallbackFrame1, fallbackFrame2]);
  waitForLocations(
    ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html"],
    fallbackLoaded
  );
}

function fallbackLoaded()
{
  dump("in fallbackLoaded\n");
  applicationCache.mozAdd("http://mochi.test:8888/tests/SimpleTest/EventUtils.js");
  OfflineTest.waitForAdd("http://mochi.test:8888/tests/SimpleTest/EventUtils.js",
      dynamicLoaded);
}

function dynamicLoaded()
{
  window.open("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html");
  // window.applicationCache.noupdate invokes implicitLoaded()
}

function implicitLoaded(aWindow, errorOccured)
{
  aWindow.close();

  OfflineTest.ok(!errorOccured, "No error on new implicit page manifest update");

  OfflineTest.waitForAdd("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html",
      implicitCached);
}

function implicitCached()
{
  // Checking first version of the manifest + another implict page caching

  // Whitelist entries
  checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/onwhitelist.html", "", true);

  // Fallback URI selection check
  checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/opp.html",
      "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html", false);
  checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/sub/opp.html",
      "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html", false);

  // Cache object status
  OfflineTest.is(applicationCache.status, SpecialPowers.Ci.nsIDOMOfflineResourceList.IDLE,
      "we have associated application cache (1)");

  OfflineTest.is(gGotFrameVersion, 1, "IFrame version 1");

  var entries = [
    // Explicit entries
    ["http://mochi.test:8888/tests/SimpleTest/SimpleTest.js", false],
    ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", true],

    // Fallback entries
    ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html", true],
    ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback2.html", false],

    // Whitelist entries
    ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/onwhitelist.html", false],

    // Implicit entries
    ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html", true],

    // Dynamic entries
    ["http://mochi.test:8888/tests/SimpleTest/EventUtils.js", true]
  ];
  OfflineTest.checkCacheEntries(
    entries,
    function() {
      ++gStep;

      OfflineTest.setSJSState("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingManifest.sjs", "second");

      applicationCache.update();
      // Invokes manifestUpdated()
    });
}

function manifestUpdated()
{
  OfflineTest.ok(gStep == 1 || gStep == 2, "Got manifestUpdated in step 1 or 2, gStep=" + gStep);

  switch (gStep)
  {
  case 1:
    // Processing second version of the manifest.

    // Whitelist entries
    checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/onwhitelist.html", "", false);

    // Fallback URI selection check
    checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/opp.html",
        "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html", false);
    checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/sub/opp.html",
        "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback2.html", false);

    // Cache object status
    OfflineTest.is(applicationCache.status, SpecialPowers.Ci.nsIDOMOfflineResourceList.UPDATEREADY,
        "we have associated application cache and update is pending (2)");

    var entries = [
      // Explicit entries
      ["http://mochi.test:8888/tests/SimpleTest/SimpleTest.js", true],
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", true],

      // Fallback entries
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html", true],
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback2.html", true],

      // Whitelist entries
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/onwhitelist.html", false],

      // Implicit entries
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html", true],

      // Dynamic entries
      ["http://mochi.test:8888/tests/SimpleTest/EventUtils.js", true]
    ];
    OfflineTest.checkCacheEntries(
      entries,
      function() {
        ++gStep;

        OfflineTest.setSJSState("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingManifest.sjs", "third");
        OfflineTest.setSJSState("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingIframe.sjs", "second");

        gGotFrameVersion = 0;
        updatingFrame.location.reload();
        // Since the frame is offline-cached, reload of it invokes update
      });

    break;

  case 2:
    // Processing third version of the manifest.

    // Whitelist entries
    checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/onwhitelist.html", "", true);

    // Fallback URI selection check
    checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/opp.html",
        "", false);
    checkFallbackAndWhitelisting("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/sub/opp.html",
        "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback2.html", false);

    // Cache object status
    OfflineTest.is(applicationCache.status, SpecialPowers.Ci.nsIDOMOfflineResourceList.UPDATEREADY,
        "we have associated application cache and update is pending (3)");

    OfflineTest.is(gGotFrameVersion, 1, "IFrame version 1 because cache was not swapped");

    var entries = [
      // Explicit entries
      ["http://mochi.test:8888/tests/SimpleTest/SimpleTest.js", false],
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", true],

      // Fallback entries
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback.html", false],
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/fallback2.html", true],

      // Whitelist entries
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/onwhitelist.html", false],

      // Implicit entries
      ["http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingImplicit.html", true],

      // Dynamic entries
      ["http://mochi.test:8888/tests/SimpleTest/EventUtils.js", true]
    ];
    OfflineTest.checkCacheEntries(
      entries,
      function() {
        ++gStep;

        applicationCache.onnoupdate = OfflineTest.priv(manifestNoUpdate);
        applicationCache.update();
        // Invokes manifestNoUpdate()
      });

    break;
  }
}

function manifestNoUpdate()
{
  applicationCache.onnoupdate = null;

  OfflineTest.ok(gStep == 3, "Got manifestNoUpdate in step 3, gStep=" + gStep);
  ++gStep;

  OfflineTest.is(applicationCache.status, SpecialPowers.Ci.nsIDOMOfflineResourceList.UPDATEREADY,
        "we have associated application cache and update is pending (4)");
  applicationCache.swapCache();
  OfflineTest.is(applicationCache.status, SpecialPowers.Ci.nsIDOMOfflineResourceList.IDLE,
        "we have associated application cache (4)");

  gGotFrameVersion = 0;
  gCallOnUpdatingFrameLoad = checkNewVersionOfIFrame;
  updatingFrame.location.reload();
}

function checkNewVersionOfIFrame()
{
  OfflineTest.is(gGotFrameVersion, 2, "IFrame version 2");

  OfflineTest.teardownAndFinish();
}

// End of the test function chain
// ==============================

SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");

if (OfflineTest.setup()) {
  applicationCache.onerror = OfflineTest.failEvent;
  applicationCache.onupdateready = OfflineTest.priv(manifestUpdated);
  applicationCache.oncached = OfflineTest.priv(manifestCached);
}

</script>

</head>

<body>
  <iframe name="updatingFrame" src="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/updatingIframe.sjs"></iframe>
  <iframe name="fallbackFrame1" src="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/opp.html"></iframe>
  <iframe name="fallbackFrame2" src="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/namespace1/sub/opp.html"></iframe>
  <iframe name="whitelistFrame" src="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/onwhitelist.html"></iframe>
</body>
</html>