summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/mochitest/test_chrome_ext_storage_cleanup.html
blob: 010769500ad2d8c0d36ef00878d1dbe46cdd699b (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
<!DOCTYPE HTML>
<html>
<head>
  <title>WebExtension test</title>
  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
  <script type="text/javascript" src="head.js"></script>
  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>

<script type="text/javascript">
"use strict";

// Test that storage used by a webextension (through localStorage,
// indexedDB, and browser.storage.local) gets cleaned up when the
// extension is uninstalled.
add_task(function* test_uninstall() {
  function writeData() {
    localStorage.setItem("hello", "world");

    let idbPromise = new Promise((resolve, reject) => {
      let req = indexedDB.open("test");
      req.onerror = e => {
        reject(new Error(`indexedDB open failed with ${e.errorCode}`));
      };

      req.onupgradeneeded = e => {
        let db = e.target.result;
        db.createObjectStore("store", {keyPath: "name"});
      };

      req.onsuccess = e => {
        let db = e.target.result;
        let transaction = db.transaction("store", "readwrite");
        let addreq = transaction.objectStore("store")
                                .add({name: "hello", value: "world"});
        addreq.onerror = addreqError => {
          reject(new Error(`add to indexedDB failed with ${addreqError.errorCode}`));
        };
        addreq.onsuccess = () => {
          resolve();
        };
      };
    });

    let browserStoragePromise = browser.storage.local.set({hello: "world"});

    Promise.all([idbPromise, browserStoragePromise]).then(() => {
      browser.test.sendMessage("finished");
    });
  }

  function readData() {
    let matchLocalStorage = (localStorage.getItem("hello") == "world");

    let idbPromise = new Promise((resolve, reject) => {
      let req = indexedDB.open("test");
      req.onerror = e => {
        reject(new Error(`indexedDB open failed with ${e.errorCode}`));
      };

      req.onupgradeneeded = e => {
        // no database, data is not present
        resolve(false);
      };

      req.onsuccess = e => {
        let db = e.target.result;
        let transaction = db.transaction("store", "readwrite");
        let addreq = transaction.objectStore("store").get("hello");
        addreq.onerror = addreqError => {
          reject(new Error(`read from indexedDB failed with ${addreqError.errorCode}`));
        };
        addreq.onsuccess = () => {
          let match = (addreq.result.value == "world");
          resolve(match);
        };
      };
    });

    let browserStoragePromise = browser.storage.local.get("hello").then(result => {
      return (Object.keys(result).length == 1 && result.hello == "world");
    });

    Promise.all([idbPromise, browserStoragePromise])
           .then(([matchIDB, matchBrowserStorage]) => {
             let result = {matchLocalStorage, matchIDB, matchBrowserStorage};
             browser.test.sendMessage("results", result);
           });
  }

  const ID = "storage.cleanup@tests.mozilla.org";

  // Use a test-only pref to leave the addonid->uuid mapping around after
  // uninstall so that we can re-attach to the same storage.  Also set
  // the pref to prevent cleaning up storage on uninstall so we can test
  // that the "keep uuid" logic works correctly.  Do the storage flag in
  // a separate prefEnv so we can pop it below, leaving the uuid flag set.
  yield SpecialPowers.pushPrefEnv({
    set: [["extensions.webextensions.keepUuidOnUninstall", true]],
  });
  yield SpecialPowers.pushPrefEnv({
    set: [["extensions.webextensions.keepStorageOnUninstall", true]],
  });

  let extension = ExtensionTestUtils.loadExtension({
    background: writeData,
    manifest: {
      applications: {gecko: {id: ID}},
      permissions: ["storage"],
    },
    useAddonManager: "temporary",
  });

  yield extension.startup();
  yield extension.awaitMessage("finished");
  yield extension.unload();

  // Check that we can still see data we wrote to storage but clear the
  // "leave storage" flag so our storaged gets cleared on uninstall.
  // This effectively tests the keepUuidOnUninstall logic, which ensures
  // that when we read storage again and check that it is cleared, that
  // it is actually a meaningful test!
  yield SpecialPowers.popPrefEnv();
  extension = ExtensionTestUtils.loadExtension({
    background: readData,
    manifest: {
      applications: {gecko: {id: ID}},
      permissions: ["storage"],
    },
    useAddonManager: "temporary",
  });

  yield extension.startup();
  let results = yield extension.awaitMessage("results");
  is(results.matchLocalStorage, true, "localStorage data is still present");
  is(results.matchIDB, true, "indexedDB data is still present");
  is(results.matchBrowserStorage, true, "browser.storage.local data is still present");

  yield extension.unload();

  // Read again.  This time, our data should be gone.
  extension = ExtensionTestUtils.loadExtension({
    background: readData,
    manifest: {
      applications: {gecko: {id: ID}},
      permissions: ["storage"],
    },
    useAddonManager: "temporary",
  });

  yield extension.startup();
  results = yield extension.awaitMessage("results");
  is(results.matchLocalStorage, false, "localStorage data was cleared");
  is(results.matchIDB, false, "indexedDB data was cleared");
  is(results.matchBrowserStorage, false, "browser.storage.local data was cleared");
  yield extension.unload();
});
</script>

</body>
</html>