Bug 1363010 - Implement browsingData.removeHistory WebExtension API method on android.
MozReview-Commit-ID: 99v6lKRNaXL
--- 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 {