Bug 1363010 - Implement browsingData.removeHistory WebExtension API method on android. draft
authorTushar Saini <tushar.saini1285@gmail.com>
Sat, 02 Sep 2017 14:05:55 +0530
changeset 657869 7ad277f99604012a6432f1ffad57ac8f8bdb2992
parent 657868 261b16827317f6edcbd5812420699c6c9754d890
child 729549 60cc172e78344618fb570161ac481c0a711e06b2
push id77652
push userbmo:tushar.saini1285@gmail.com
push dateSat, 02 Sep 2017 08:57:52 +0000
bugs1363010
milestone57.0a1
Bug 1363010 - Implement browsingData.removeHistory WebExtension API method on android. MozReview-Commit-ID: 99v6lKRNaXL
mobile/android/components/extensions/ext-browsingData.js
mobile/android/components/extensions/schemas/browsing_data.json
mobile/android/components/extensions/test/mochitest/chrome.ini
mobile/android/components/extensions/test/mochitest/test_ext_browsingData_history.html
mobile/android/modules/Sanitizer.jsm
--- a/mobile/android/components/extensions/ext-browsingData.js
+++ b/mobile/android/components/extensions/ext-browsingData.js
@@ -95,12 +95,15 @@ this.browsingData = class extends Extens
           return Sanitizer.clearItem("cache");
         },
         removeDownloads(options) {
           return Sanitizer.clearItem("downloadHistory", options.since);
         },
         removeFormData(options) {
           return Sanitizer.clearItem("formdata", options.since);
         },
+        removeHistory(options) {
+          return Sanitizer.clearItem("history", options.since);
+        },
       },
     };
   }
 };
--- a/mobile/android/components/extensions/schemas/browsing_data.json
+++ b/mobile/android/components/extensions/schemas/browsing_data.json
@@ -298,17 +298,16 @@
           }
         ]
       },
       {
         "name": "removeHistory",
         "description": "Clears the browser's history.",
         "type": "function",
         "async": "callback",
-        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
--- a/mobile/android/components/extensions/test/mochitest/chrome.ini
+++ b/mobile/android/components/extensions/test/mochitest/chrome.ini
@@ -5,13 +5,14 @@ support-files =
 tags = webextensions
 
 [test_ext_activeTab_permission.html]
 [test_ext_browserAction_getTitle_setTitle.html]
 [test_ext_browserAction_onClicked.html]
 [test_ext_browsingData_cookies_cache.html]
 [test_ext_browsingData_downloads.html]
 [test_ext_browsingData_formdata.html]
+[test_ext_browsingData_history.html]
 [test_ext_browsingData_settings.html]
 [test_ext_options_ui.html]
 [test_ext_pageAction_show_hide.html]
 [test_ext_pageAction_getPopup_setPopup.html]
 skip-if = os == 'android' # bug 1373170
new file mode 100644
--- /dev/null
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_history.html
@@ -0,0 +1,157 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>BrowsingData History test</title>
+  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+  <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+"use strict";
+
+const {utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/osfile.jsm");
+Cu.import("resource://gre/modules/Sqlite.jsm");
+
+const DB_PATH = OS.Path.join(OS.Constants.Path.profileDir, "browser.db");
+
+const DATE = (new Date()).getTime();
+
+let historyEntry = {
+  url: "https://www.test.com",
+  guid : "hjdsas"
+}
+
+let visitEntry = {
+  history_guid: "hkkp123",
+  visit_type: 1
+}
+
+async function check() {
+  // Open new connextion to db
+  const db = await Sqlite.openConnection({path: DB_PATH, sharedMemoryCache: false});
+  // Check table exists
+  ok((db.tableExists("history")), 'history table exists.');
+  ok((db.tableExists("visits")), 'visits table exists.');
+
+  let result = await db.execute("SELECT * FROM history", null, function onRow(row) {
+        is(row.getResultByName("url"), "", "expected url");
+        is(row.getResultByName("visits"), 0, "expected visit counts");
+        is(row.getResultByName("date"), 0, "expected date");
+        is(row.getResultByName("guid"), HISTORY_ENTRY.guid, "expected guid");
+      });
+
+  result = await db.execute("SELECT * FROM history");
+  is(result.length, 1, "History table has expected no of rows");
+
+  result = await db.execute("SELECT * FROM visits");
+  is(result.length, 0, "Visit table has expected no of rows");
+
+  await db.close();
+  await new Promise(resolve => setTimeout(resolve, 10000));
+}
+
+async function setupHistory() {
+    const db = await Sqlite.openConnection({path: DB_PATH, sharedMemoryCache: false});
+
+  // Set Up History: We will add one history items along with 4 visits for it in visit table
+  // Table Exists
+  ok((db.tableExists("history")), 'history table exists.');
+  ok((db.tableExists("visits")), 'visits table exists.');
+
+  // Clear history table
+  await db.execute("delete from history");
+
+  // funtion insert fake history items  
+  await db.executeCached(
+            `INSERT OR IGNORE INTO history (url, visits, visits_local, visits_remote, date, date_local, date_remote, guid)
+            VALUES (:url, :visits, :visits_local, :visits_remote, :date, :date_local, :date_remote, :guid)`, HISTORY_ENTRY);
+
+  let result = await db.execute("SELECT * FROM history", null, function onRow(row) {
+      is(row.getResultByName("url"), HISTORY_ENTRY.url, "expected url");
+      is(row.getResultByName("visits"), HISTORY_ENTRY.visits, "expected visit counts");
+      is(row.getResultByName("visits_local"), HISTORY_ENTRY.visits_local, "expected visit local");
+      is(row.getResultByName("visits_remote"), HISTORY_ENTRY.visits_remote, "expected visit remote");
+      is(row.getResultByName("date"), HISTORY_ENTRY.date, "expected date");
+      is(row.getResultByName("date_local"), HISTORY_ENTRY.date_local, "expected local date");
+      is(row.getResultByName("date_remote"), HISTORY_ENTRY.date_remote, "expected remote date");
+      is(row.getResultByName("guid"), HISTORY_ENTRY.guid, "expected guid");
+    });
+  result = await db.execute("SELECT * FROM history");
+  is(result.length, 1, "fake history items inserted successfully!");
+  
+  // Set up visit table
+  // Clear visits table
+  await db.execute("delete from visits");
+
+  // Add two remote visits
+  VISIT_ENTRY.date = 1500100;
+  VISIT_ENTRY.is_local = 0;
+
+  await db.executeCached(
+            `INSERT INTO visits (history_guid, visit_type, date, is_local) VALUES (:history_guid, :visit_type, :date, :is_local)`, VISIT_ENTRY);
+
+  VISIT_ENTRY.date = 1500600;
+  
+  await db.executeCached(
+            `INSERT INTO visits (history_guid, visit_type, date, is_local) VALUES (:history_guid, :visit_type, :date, :is_local)`, VISIT_ENTRY);
+
+  // Add two local visits
+  VISIT_ENTRY.date = 1500200;
+  VISIT_ENTRY.is_local = 1;
+
+  await db.executeCached(
+            `INSERT INTO visits (history_guid, visit_type, date, is_local) VALUES (:history_guid, :visit_type, :date, :is_local)`, VISIT_ENTRY);
+
+  VISIT_ENTRY.date = 1500800;
+
+  await db.executeCached(
+            `INSERT INTO visits (history_guid, visit_type, date, is_local) VALUES (:history_guid, :visit_type, :date, :is_local)`, VISIT_ENTRY);
+
+  result = await db.execute("SELECT * FROM visits");
+  is(result.length, 4, "fake visit items inserted successfully!");
+
+  await db.close();
+}
+
+add_task(async function testHistory() {
+  function background() {
+    browser.test.onMessage.addListener(async (msg, options) => {
+      if (msg == "removeHistory") {
+        await browser.browsingData.removeHistory(options);
+      }
+      browser.test.sendMessage("historyRemoved");
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: {
+      permissions: ["browsingData"],
+    },
+  });
+
+  async function testRemovalMethod(method) {
+    await setupHistory();
+    // Remove all items from history 
+    extension.sendMessage(method, { since: 0 });
+    await extension.awaitMessage("historyRemoved");
+    await check();
+    //await extension.awaitMessage("historyRemoved");
+  }
+
+  await extension.startup();
+  
+  await testRemovalMethod("removeHistory")
+
+  await extension.unload();
+});
+
+</script>
+
+</body>
--- a/mobile/android/modules/Sanitizer.jsm
+++ b/mobile/android/modules/Sanitizer.jsm
@@ -41,16 +41,19 @@ Sanitizer.prototype = {
         // Normal call to DownloadFiles remove actual data from storage, but our web-extension consumer
         // deletes only download history. So, for this reason we are passing a flag 'deleteFiles'.
         case "downloadHistory":
           this._clear("downloadFiles", { startTime, deleteFiles: false });
           break;
         case "formdata":
           this._clear(aItemName, { startTime });
           break;
+        case "history":
+          this._clear(aItemName, { startTime });
+          break;
         default:
           return Promise.reject({message: `Invalid argument: ${aItemName} does not support startTime argument.`});
       }
     } else {
       this._clear(aItemName);
     }
   },
 
@@ -166,21 +169,21 @@ Sanitizer.prototype = {
       },
 
       get canClear() {
           return true;
       }
     },
 
     history: {
-      clear: function() {
+      clear: function({ startTime: 0 } = {}) {
         let refObj = {};
         TelemetryStopwatch.start("FX_SANITIZE_HISTORY", refObj);
 
-        return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:ClearHistory" })
+        return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:ClearHistory", startTime })
           .catch(e => Cu.reportError("Java-side history clearing failed: " + e))
           .then(function() {
             TelemetryStopwatch.finish("FX_SANITIZE_HISTORY", refObj);
             try {
               Services.obs.notifyObservers(null, "browser:purge-session-history");
             } catch (e) { }
 
             try {