summaryrefslogtreecommitdiffstats
path: root/dom/cache/test/mochitest/test_cache_updateUsage.html
blob: 5abc080f14c9368a23bb239cf54cf59566c95275 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<!-- Any copyright is dedicated to the Public Domain.
   - http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
  <title>Test Cache update its usage to QuotaManager</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="large_url_list.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">
function setupTestIframe() {
  return new Promise(function(resolve) {
    var iframe = document.createElement("iframe");
    iframe.src = "empty.html";
    iframe.onload = function() {
      window.caches = iframe.contentWindow.caches;
      resolve();
    };
    document.body.appendChild(iframe);
  });
}

function clearStorage() {
  return new Promise(function(resolve, reject) {
    var qms = SpecialPowers.Services.qms;
    var principal = SpecialPowers.wrap(document).nodePrincipal;
    var request = qms.clearStoragesForPrincipal(principal);
    var cb = SpecialPowers.wrapCallback(resolve);
    request.callback = cb;
  });
}

function resetStorage() {
  return new Promise(function(resolve, reject) {
    var qms = SpecialPowers.Services.qms;
    var request = qms.reset();
    var cb = SpecialPowers.wrapCallback(resolve);
    request.callback = cb;
  });
}

function getStorageUsage(fromMemory) {
  return new Promise(function(resolve, reject) {
    var qms = SpecialPowers.Services.qms;
    var principal = SpecialPowers.wrap(document).nodePrincipal;
    var cb = SpecialPowers.wrapCallback(function(request) {
      var result = request.result;
      resolve(result.usage);
    });

    // Actually, the flag is used to distingulish getting group usage and origin
    // usage, but we utilize this to get usage from in-memory and the disk.
    // Default value for "fromMemory" is false.
    qms.getUsageForPrincipal(principal, cb, !!fromMemory);
  });
}

async function verifyUsage() {
  // Although it returns group usage when passing true, it calculate the usage
  // from tracking usage object (in-memory object) in QuotaManager.
  let memoryUsage = await getStorageUsage(/* fromMemory */ true);
  // This will returns the origin usage by re-calculating usage from directory.
  let diskUsage = await getStorageUsage(/* fromMemory */ false);

  is(memoryUsage, diskUsage,
     "In-memory usage and disk usage should be the same.");
  return memoryUsage;
}

async function waitForIOToComplete(cache, request) {
  info("Wait for IO complete.");
  // The following lines ensure we've deleted orphaned body.
  // First, wait for cache operation delete the orphaned body.
  await cache.match(request);

  // Finally, wait for -wal file finish its job.
  return resetStorage();
}

SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
  "set": [["dom.caches.enabled", true],
          ["dom.caches.testing.enabled", true],
          ["dom.quotaManager.testing", true],
          ["privacy.partition.always_partition_third_party_non_cookie_storage", false]],
}, async function() {
  // Bug 1746646: Make mochitests work with TCP enabled (cookieBehavior = 5)
  // Acquire storage access permission here so that the Cache API is avaialable
  SpecialPowers.wrap(document).notifyUserGestureActivation();
  await SpecialPowers.addPermission("storageAccessAPI", true, window.location.href);
  await SpecialPowers.wrap(document).requestStorageAccess();

  const name = "cacheUpdateUsage";
  const url = "test_cache_add.js";
  const other_url = "test_cache_put.js";

  // This test mainly ensure DOM Cache updates its usage to QuotaManager when
  // executing an operation which creates/deletes files. To do this, we verify
  // usage by calling getUsageFromPrincipal twice with different flag(aGroup).
  // The reason is we get group usage by collecting in-memory data, and getting
  // origin usage by collecting storage usage from files.

  await setupTestIframe();

  info("Stage 1: Clean storage.");
  await clearStorage();
  await verifyUsage();

  info("Stage 2: Verify CacheStorage.");
  info("Stage 2.1: Verify caches.open.");
  await caches.open(name);
  await verifyUsage();

  info("Stage 2.2: Verify caches.delete.");
  var deleted = await caches.delete(name);
  ok(deleted, "Cache storage should be deleted");
  // Reference from test_cache_orphanced_body.html. It ensures that all
  // the runnables have been flushed through the threads.
  await caches.has(name);
  await resetStorage();
  await verifyUsage();

  info("Stage 3: Verify Cache.");
  let cache = await caches.open(name);
  info("Stage 3.1: Verify cache.addAll.");
  await cache.addAll([url, other_url]);
  await verifyUsage();
  info("Stage 3.1.1: Delete all cached requests.");
  await cache.delete(url);
  await cache.delete(other_url);
  await waitForIOToComplete(cache, other_url);
  let emptyUsage1 = await verifyUsage();

  info("Stage 3.2: Verify cache.add.");
  cache = await caches.open(name);
  await cache.add(url);
  await verifyUsage();
  info("Stage 3.2.1: Delete cache.");
  await cache.delete(url);
  await waitForIOToComplete(cache, url);
  let emptyUsage2 = await verifyUsage();

  info("Stage 3.3: Verify cache.put.");
  cache = await caches.open(name);
  let response = await fetch(other_url);
  await cache.put(other_url, response);
  await verifyUsage();
  info("Stage 3.3.1: Delete cache.");
  await cache.delete(other_url);
  await waitForIOToComplete(cache, other_url);
  let emptyUsage3 = await verifyUsage();

  // Adding same requests twice will make Cache create morgue file twice, and
  // then delete the previous one.
  info("Stage 4: Add same request twice to make removing a morgue file.");
  cache = await caches.open(name);
  info("Stage 4.1: First cache.add.");
  await cache.add(url);
  await verifyUsage();

  info("Stage 4.2: Second cache.add.");
  await cache.add(url);

  // Since we trigger the action to delete orphaned body, we need to wait for
  // the action is done.
  await waitForIOToComplete(cache, url);
  await verifyUsage();
  cache = await caches.open(name);
  info("Stage 4.2.1: cache.delete.");
  await cache.delete(url);
  await waitForIOToComplete(cache, url);
  let emptyUsage4 = await verifyUsage();

  info("Stage 5: Clean caches.");
  await caches.delete(name);

  info("Stage 6: Final Check.");
  ok(emptyUsage1 == emptyUsage2 &&
     emptyUsage1 == emptyUsage3 &&
     emptyUsage1 == emptyUsage4,
     "Empty usages should be the same");

  await SimpleTest.finish();
});
</script>
</body>
</html>