From 84895794b3d439436d27bfd80e7aea90cd2bf15a Mon Sep 17 00:00:00 2001 From: Erica Wright Date: Thu, 11 Jul 2019 03:01:18 +0000 Subject: [PATCH] Bug 1557058 - use real data for protection report graph r=johannh Differential Revision: https://phabricator.services.mozilla.com/D36249 --HG-- extra : moz-landing-system : lando --- .../about/AboutProtectionsHandler.jsm | 51 +++- .../test/browser/browser_aboutURLs.js | 3 + .../protections/content/protections.css | 27 +- .../protections/content/protections.html | 6 +- .../protections/content/protections.js | 132 ++++----- browser/components/protections/moz.build | 2 + .../protections/test/browser/browser.ini | 5 + .../browser/browser_protections_report_ui.js | 251 ++++++++++++++++++ .../antitracking/TrackingDBService.jsm | 12 + .../antitracking/nsITrackingDBService.idl | 7 + .../test/xpcshell/test_tracking_db_service.js | 83 ++++++ 11 files changed, 475 insertions(+), 104 deletions(-) create mode 100644 browser/components/protections/test/browser/browser.ini create mode 100644 browser/components/protections/test/browser/browser_protections_report_ui.js diff --git a/browser/components/about/AboutProtectionsHandler.jsm b/browser/components/about/AboutProtectionsHandler.jsm index 52d330dfeb0e..40d3220a9ea2 100644 --- a/browser/components/about/AboutProtectionsHandler.jsm +++ b/browser/components/about/AboutProtectionsHandler.jsm @@ -5,16 +5,32 @@ "use strict"; var EXPORTED_SYMBOLS = ["AboutProtectionsHandler"]; - +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); const { RemotePages } = ChromeUtils.import( "resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm" ); +XPCOMUtils.defineLazyServiceGetter( + this, + "TrackingDBService", + "@mozilla.org/tracking-db-service;1", + "nsITrackingDBService" +); + +let idToTextMap = new Map([ + [Ci.nsITrackingDBService.TRACKERS_ID, "tracker"], + [Ci.nsITrackingDBService.TRACKING_COOKIES_ID, "cookie"], + [Ci.nsITrackingDBService.CRYPTOMINERS_ID, "cryptominer"], + [Ci.nsITrackingDBService.FINGERPRINTERS_ID, "fingerprinter"], +]); var AboutProtectionsHandler = { _inited: false, - _topics: ["openContentBlockingPreferences"], + _topics: ["OpenContentBlockingPreferences", "FetchContentBlockingEvents"], init() { + this.receiveMessage = this.receiveMessage.bind(this); this.pageListener = new RemotePages("about:protections"); for (let topic of this._topics) { this.pageListener.addMessageListener(topic, this.receiveMessage); @@ -35,11 +51,40 @@ var AboutProtectionsHandler = { receiveMessage(aMessage) { let win = aMessage.target.browser.ownerGlobal; switch (aMessage.name) { - case "openContentBlockingPreferences": + case "OpenContentBlockingPreferences": win.openPreferences("privacy-trackingprotection", { origin: "about-protections", }); break; + case "FetchContentBlockingEvents": + TrackingDBService.getEventsByDateRange( + aMessage.data.from, + aMessage.data.to + ).then(results => { + let dataToSend = {}; + let largest = 0; + for (let result of results) { + let count = result.getResultByName("count"); + let type = result.getResultByName("type"); + let timestamp = result.getResultByName("timestamp"); + dataToSend[timestamp] = dataToSend[timestamp] || { total: 0 }; + dataToSend[timestamp][idToTextMap.get(type)] = count; + dataToSend[timestamp].total += count; + // Record the largest amount of tracking events found per day, + // to create the tallest column on the graph and compare other days to. + if (largest < dataToSend[timestamp].total) { + largest = dataToSend[timestamp].total; + } + } + dataToSend.largest = largest; + if (aMessage.target.browser) { + aMessage.target.sendAsyncMessage( + "SendContentBlockingRecords", + dataToSend + ); + } + }); + break; } }, }; diff --git a/browser/components/contextualidentity/test/browser/browser_aboutURLs.js b/browser/components/contextualidentity/test/browser/browser_aboutURLs.js index 197b8f8ba19e..5c9856136288 100644 --- a/browser/components/contextualidentity/test/browser/browser_aboutURLs.js +++ b/browser/components/contextualidentity/test/browser/browser_aboutURLs.js @@ -29,6 +29,9 @@ add_task(async function() { // about:debugging requires specific wait code for internal pending RDP requests. "debugging", "debugging-new", + // about:protections uses RPM to send a message as soon as the page loads, + // the page is destoryed before getting a response. + "protections", ]; for (let cid in Cc) { diff --git a/browser/components/protections/content/protections.css b/browser/components/protections/content/protections.css index 4929f8d391c0..0f8184a899ca 100644 --- a/browser/components/protections/content/protections.css +++ b/browser/components/protections/content/protections.css @@ -11,8 +11,8 @@ --card-padding: 22px; --social-color: #AB71FF; --social-color-darker: #7F27FF; - --crossSite-color: #0090F4; - --crossSite-color-darker: #0073C3; + --cookie-color: #0090F4; + --cookie-color-darker: #0073C3; --tracker-color: #2AC3A2; --tracker-color-darker: #229C82; --fingerprinter-color: #FFBD4F; @@ -32,8 +32,8 @@ body[focuseddatatype=social] { --tab-highlight: var(--social-color); } -body[focuseddatatype=crossSite] { - --tab-highlight: var(--crossSite-color); +body[focuseddatatype=cookie] { + --tab-highlight: var(--cookie-color); } body[focuseddatatype=tracker] { @@ -172,12 +172,12 @@ body[focuseddatatype=cryptominer] { background-color: var(--social-color-darker); } -.crossSite-bar { - background-color: var(--crossSite-color); +.cookie-bar { + background-color: var(--cookie-color); } -.hover-crossSite .crossSite-bar { - background-color: var(--crossSite-color-darker); +.hover-cookie .cookie-bar { + background-color: var(--cookie-color-darker); } .tracker-bar { @@ -232,10 +232,11 @@ label[data-type="social"] { color: var(--social-color); } -label[data-type="crossSite"] { +label[data-type="cookie"] { + color: var(--cookie-color); background-image: url(chrome://browser/skin/controlcenter/3rdpartycookies.svg); - fill: var(--crossSite-color); - color: var(--crossSite-color); + fill: var(--cookie-color); + color: var(--cookie-color); } label[data-type="tracker"] { @@ -257,7 +258,7 @@ label[data-type="cryptominer"] { } .hover-social label[for="tab-social"], -.hover-crossSite label[for="tab-crossSite"], +.hover-cookie label[for="tab-cookie"], .hover-tracker label[for="tab-tracker"], .hover-fingerprinter label[for="tab-fingerprinter"], .hover-cryptominer label[for="tab-cryptominer"], @@ -290,7 +291,7 @@ label:hover { } #tab-social:checked ~ #social, -#tab-crossSite:checked ~ #crossSite, +#tab-cookie:checked ~ #cookie, #tab-tracker:checked ~ #tracker, #tab-fingerprinter:checked ~ #fingerprinter, #tab-cryptominer:checked ~ #cryptominer { diff --git a/browser/components/protections/content/protections.html b/browser/components/protections/content/protections.html index 77f5b591fa8f..e1eb35376ece 100644 --- a/browser/components/protections/content/protections.html +++ b/browser/components/protections/content/protections.html @@ -43,8 +43,8 @@ - - + + @@ -59,7 +59,7 @@

Social Media Trackers

Social media like, post, and comment buttons on other websites can track you — even if you don’t use them. Logging in to sites using your Facebook or Twitter account is another way they can track what you do on those sites. We remove these trackers so Facebook and Twitter see less of what you do online.

-
+ diff --git a/browser/components/protections/content/protections.js b/browser/components/protections/content/protections.js index 60dd2445ea1d..e2eed4b57de4 100644 --- a/browser/components/protections/content/protections.js +++ b/browser/components/protections/content/protections.js @@ -5,114 +5,74 @@ /* eslint-env mozilla/frame-script */ document.addEventListener("DOMContentLoaded", e => { + let todayInMs = Date.now(); + let weekAgoInMs = todayInMs - 7 * 24 * 60 * 60 * 1000; + RPMSendAsyncMessage("FetchContentBlockingEvents", { + from: weekAgoInMs, + to: todayInMs, + }); + let dataTypes = [ "cryptominer", "fingerprinter", "tracker", - "crossSite", + "cookie", "social", ]; let weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - let today = new Date().getDay(); let protectionDetails = document.getElementById("protection-details"); protectionDetails.addEventListener("click", () => { - RPMSendAsyncMessage("openContentBlockingPreferences"); + RPMSendAsyncMessage("OpenContentBlockingPreferences"); }); - let data = [ - { - total: 41, - cryptominer: 1, - fingerprinter: 10, - tracker: 15, - crossSite: 12, - social: 3, - }, - { - total: 246, - cryptominer: 5, - fingerprinter: 8, - tracker: 110, - crossSite: 103, - social: 20, - }, - { - total: 59, - cryptominer: 0, - fingerprinter: 1, - tracker: 25, - crossSite: 25, - social: 8, - }, - { - total: 177, - cryptominer: 0, - fingerprinter: 4, - tracker: 24, - crossSite: 136, - social: 13, - }, - { - total: 16, - cryptominer: 1, - fingerprinter: 3, - tracker: 0, - crossSite: 7, - social: 5, - }, - { - total: 232, - cryptominer: 0, - fingerprinter: 30, - tracker: 84, - crossSite: 86, - social: 32, - }, - { - total: 153, - cryptominer: 0, - fingerprinter: 10, - tracker: 35, - crossSite: 95, - social: 13, - }, - ]; - - // Use this to populate the graph with real data in the future. - let createGraph = () => { - let largest = 10; - for (let day of data) { - if (largest < day.total) { - largest = day.total; - } + let createGraph = data => { + // Set a default top size for the height of the graph bars so that small + // numbers don't fill the whole graph. + let largest = 100; + if (largest < data.largest) { + largest = data.largest; } let graph = document.getElementById("graph"); - for (let i = 0; i < weekdays.length; i++) { + for (let i = weekdays.length - 1; i >= 0; i--) { + // Start 7 days ago and count down to today. + let date = new Date(); + date.setDate(date.getDate() - i); + let dateString = date.toISOString().split("T")[0]; let bar = document.createElement("div"); bar.className = "graph-bar"; - let barHeight = (data[i].total / largest) * 100; - bar.style.height = `${barHeight}%`; - for (let type of dataTypes) { - let dataHeight = (data[i][type] / data[i].total) * 100; - let div = document.createElement("div"); - div.className = `${type}-bar`; - div.setAttribute("data-type", type); - div.style.height = `${dataHeight}%`; - bar.appendChild(div); + if (data[dateString]) { + let content = data[dateString]; + let barHeight = (content.total / largest) * 100; + bar.style.height = `${barHeight}%`; + for (let type of dataTypes) { + if (content[type]) { + let dataHeight = (content[type] / content.total) * 100; + let div = document.createElement("div"); + div.className = `${type}-bar`; + div.setAttribute("data-type", type); + div.style.height = `${dataHeight}%`; + bar.appendChild(div); + } + } + } else { + // There were no content blocking events on this day. + bar.style.height = `0`; } graph.appendChild(bar); let label = document.createElement("span"); label.className = "column-label"; if (i == 6) { - label.innerText = "Today"; + label.textContent = "Today"; } else { - label.innerText = weekdays[(i + today) % 7]; + label.textContent = weekdays[(i + 1 + new Date().getDay()) % 7]; } - graph.appendChild(label); + graph.prepend(label); } + + addListeners(); }; let addListeners = () => { @@ -130,7 +90,7 @@ document.addEventListener("DOMContentLoaded", e => { }); wrapper.addEventListener("click", ev => { - if (ev.originalTarget.dataset) { + if (ev.originalTarget.dataset.type) { document.getElementById(`tab-${ev.target.dataset.type}`).click(); } }); @@ -143,6 +103,8 @@ document.addEventListener("DOMContentLoaded", e => { }); } }; - createGraph(); - addListeners(); + + RPMAddMessageListener("SendContentBlockingRecords", message => { + createGraph(message.data); + }); }); diff --git a/browser/components/protections/moz.build b/browser/components/protections/moz.build index f7c39a50c5d7..8677df18933f 100644 --- a/browser/components/protections/moz.build +++ b/browser/components/protections/moz.build @@ -4,6 +4,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini'] + JAR_MANIFESTS += ['jar.mn'] with Files('**'): diff --git a/browser/components/protections/test/browser/browser.ini b/browser/components/protections/test/browser/browser.ini new file mode 100644 index 000000000000..0a200d1c7dd2 --- /dev/null +++ b/browser/components/protections/test/browser/browser.ini @@ -0,0 +1,5 @@ +[DEFAULT] +support-files = + !/browser/base/content/test/trackingUI/trackingPage.html + +[browser_protections_report_ui.js] diff --git a/browser/components/protections/test/browser/browser_protections_report_ui.js b/browser/components/protections/test/browser/browser_protections_report_ui.js new file mode 100644 index 000000000000..8cda3b8dd140 --- /dev/null +++ b/browser/components/protections/test/browser/browser_protections_report_ui.js @@ -0,0 +1,251 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Note: This test may cause intermittents if run at exactly midnight. + +const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm"); +const { Sqlite } = ChromeUtils.import("resource://gre/modules/Sqlite.jsm"); +XPCOMUtils.defineLazyServiceGetter( + this, + "TrackingDBService", + "@mozilla.org/tracking-db-service;1", + "nsITrackingDBService" +); + +XPCOMUtils.defineLazyGetter(this, "DB_PATH", function() { + return OS.Path.join(OS.Constants.Path.profileDir, "protections.sqlite"); +}); + +const SQL = { + insertCustomTimeEvent: + "INSERT INTO events (type, count, timestamp)" + + "VALUES (:type, :count, date(:timestamp));", + + selectAll: "SELECT * FROM events", +}; + +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.contentblocking.database.enabled", true]], + }); +}); + +add_task(async function test_graph_display() { + // This creates the schema. + await TrackingDBService.saveEvents(JSON.stringify({})); + let db = await Sqlite.openConnection({ path: DB_PATH }); + + let date = new Date().toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKERS_ID, + count: 1, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.CRYPTOMINERS_ID, + count: 2, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.FINGERPRINTERS_ID, + count: 3, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKING_COOKIES_ID, + count: 4, + timestamp: date, + }); + + date = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKERS_ID, + count: 4, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.CRYPTOMINERS_ID, + count: 3, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.FINGERPRINTERS_ID, + count: 2, + timestamp: date, + }); + + date = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKERS_ID, + count: 4, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.CRYPTOMINERS_ID, + count: 3, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKING_COOKIES_ID, + count: 1, + timestamp: date, + }); + + date = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKERS_ID, + count: 3, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.FINGERPRINTERS_ID, + count: 2, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKING_COOKIES_ID, + count: 1, + timestamp: date, + }); + + date = new Date(Date.now() - 4 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.CRYPTOMINERS_ID, + count: 2, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.FINGERPRINTERS_ID, + count: 2, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKING_COOKIES_ID, + count: 1, + timestamp: date, + }); + + date = new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKERS_ID, + count: 3, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.CRYPTOMINERS_ID, + count: 3, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.FINGERPRINTERS_ID, + count: 2, + timestamp: date, + }); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKING_COOKIES_ID, + count: 8, + timestamp: date, + }); + + let tab = await BrowserTestUtils.openNewForegroundTab({ + url: "about:protections", + gBrowser, + }); + await ContentTask.spawn(tab.linkedBrowser, {}, async function() { + const DATA_TYPES = ["cryptominer", "fingerprinter", "tracker", "cookie"]; + let allBars = null; + await ContentTaskUtils.waitForCondition(() => { + allBars = content.document.querySelectorAll(".graph-bar"); + return allBars.length; + }, "The graph has been built"); + + is(allBars.length, 7, "7 bars have been found on the graph"); + + // today has each type + // yesterday will have no tracking cookies + // 2 days ago will have no fingerprinters + // 3 days ago will have no cryptominers + // 4 days ago will have no trackers + // 5 days ago will have no social (when we add social) + // 6 days ago will be empty + is( + allBars[6].childNodes.length, + DATA_TYPES.length, + "today has all of the data types shown" + ); + is( + allBars[6].querySelector(".tracker-bar").style.height, + "10%", + "trackers take 10%" + ); + is( + allBars[6].querySelector(".cryptominer-bar").style.height, + "20%", + "cryptominers take 20%" + ); + is( + allBars[6].querySelector(".fingerprinter-bar").style.height, + "30%", + "fingerprinters take 30%" + ); + is( + allBars[6].querySelector(".cookie-bar").style.height, + "40%", + "cross site tracking cookies take 40%" + ); + + is( + allBars[5].childNodes.length, + DATA_TYPES.length - 1, + "1 day ago is missing one type" + ); + ok( + !allBars[5].querySelector(".cookie-bar"), + "there is no cross site tracking cookie section 1 day ago." + ); + + is( + allBars[4].childNodes.length, + DATA_TYPES.length - 1, + "2 days ago is missing one type" + ); + ok( + !allBars[4].querySelector(".fingerprinter-bar"), + "there is no fingerprinter section 1 day ago." + ); + + is( + allBars[3].childNodes.length, + DATA_TYPES.length - 1, + "3 days ago is missing one type" + ); + ok( + !allBars[3].querySelector(".cryptominer-bar"), + "there is no cryptominer section 1 day ago." + ); + + is( + allBars[2].childNodes.length, + DATA_TYPES.length - 1, + "4 days ago is missing one type" + ); + ok( + !allBars[2].querySelector(".tracker-bar"), + "there is no tracker section 1 day ago." + ); + + // TODO test for social missing + + is(allBars[0].childNodes.length, 0, "6 days ago has no content"); + is(allBars[0].style.height, "0px", "6 days ago has no height"); + }); + + // Use the TrackingDBService API to delete the data. + await TrackingDBService.clearAll(); + // Make sure the data was deleted. + let rows = await db.execute(SQL.selectAll); + is(rows.length, 0, "length is 0"); + await db.close(); + BrowserTestUtils.removeTab(tab); +}); diff --git a/toolkit/components/antitracking/TrackingDBService.jsm b/toolkit/components/antitracking/TrackingDBService.jsm index 387c64e644b3..f4b704a8279b 100644 --- a/toolkit/components/antitracking/TrackingDBService.jsm +++ b/toolkit/components/antitracking/TrackingDBService.jsm @@ -52,6 +52,10 @@ const SQL = { deleteEventsRecords: "DELETE FROM events;", removeRecordsSince: "DELETE FROM events WHERE timestamp >= date(:date);", + + selectByDateRange: + "SELECT * FROM events " + + "WHERE timestamp BETWEEN date(:dateFrom) AND date(:dateTo);", }; /** @@ -242,8 +246,16 @@ TrackingDBService.prototype = { async clearSince(date) { let db = await this.ensureDB(); + date = new Date(date).toISOString(); await removeRecordsSince(db, date); }, + + async getEventsByDateRange(dateFrom, dateTo) { + let db = await this.ensureDB(); + dateFrom = new Date(dateFrom).toISOString(); + dateTo = new Date(dateTo).toISOString(); + return db.execute(SQL.selectByDateRange, { dateFrom, dateTo }); + }, }; var EXPORTED_SYMBOLS = ["TrackingDBService"]; diff --git a/toolkit/components/antitracking/nsITrackingDBService.idl b/toolkit/components/antitracking/nsITrackingDBService.idl index d60dfb6cf8fe..ecd685f08ea3 100644 --- a/toolkit/components/antitracking/nsITrackingDBService.idl +++ b/toolkit/components/antitracking/nsITrackingDBService.idl @@ -38,6 +38,13 @@ interface nsITrackingDBService : nsISupports */ Promise clearSince(in int64_t since); + /** + * Fetch events from the content blocking database + * @param dateFrom a unix timestamp. + * @param dateTo a unix timestamp. + */ + Promise getEventsByDateRange(in int64_t dateFrom, in int64_t dateTo); + const unsigned long OTHER_COOKIES_BLOCKED_ID = 0; const unsigned long TRACKERS_ID = 1; const unsigned long TRACKING_COOKIES_ID = 2; diff --git a/toolkit/components/antitracking/test/xpcshell/test_tracking_db_service.js b/toolkit/components/antitracking/test/xpcshell/test_tracking_db_service.js index b0ab2266807e..5846bf22fc5d 100644 --- a/toolkit/components/antitracking/test/xpcshell/test_tracking_db_service.js +++ b/toolkit/components/antitracking/test/xpcshell/test_tracking_db_service.js @@ -1,3 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Note: This test may cause intermittents if run at exactly midnight. + "use strict"; const { XPCOMUtils } = ChromeUtils.import( @@ -266,3 +272,80 @@ add_task(async function test_timestamp_aggragation() { await db.close(); Services.prefs.clearUserPref("browser.contentblocking.database.enabled"); }); + +// This tests that TrackingDBService.getEventsByDateRange can accept two timestamps in unix epoch time +// and return entries that occur within the timestamps, rounded to the nearest day and inclusive. +add_task(async function test_getEventsByDateRange() { + Services.prefs.setBoolPref("browser.contentblocking.database.enabled", true); + // This creates the schema. + await TrackingDBService.saveEvents(JSON.stringify({})); + let db = await Sqlite.openConnection({ path: DB_PATH }); + + let d = new Date(1521009000000); + let date = d.toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.CRYPTOMINERS_ID, + count: 3, + timestamp: date, + }); + + date = new Date(d - 2 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKERS_ID, + count: 2, + timestamp: date, + }); + + date = new Date(d - 3 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKING_COOKIES_ID, + count: 2, + timestamp: date, + }); + + date = new Date(d - 4 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.TRACKING_COOKIES_ID, + count: 2, + timestamp: date, + }); + + date = new Date(d - 9 * 24 * 60 * 60 * 1000).toISOString(); + await db.execute(SQL.insertCustomTimeEvent, { + type: TrackingDBService.FINGERPRINTERS_ID, + count: 2, + timestamp: date, + }); + + let daysBefore1 = new Date(d - 24 * 60 * 60 * 1000); + let daysBefore4 = new Date(d - 4 * 24 * 60 * 60 * 1000); + let daysBefore9 = new Date(d - 9 * 24 * 60 * 60 * 1000); + + let events = await TrackingDBService.getEventsByDateRange(daysBefore1, d); + equal( + events.length, + 1, + "There is 1 event entry between the date and one day before, inclusive" + ); + + events = await TrackingDBService.getEventsByDateRange(daysBefore4, d); + equal( + events.length, + 4, + "There is 4 event entries between the date and four days before, inclusive" + ); + + events = await TrackingDBService.getEventsByDateRange( + daysBefore9, + daysBefore4 + ); + equal( + events.length, + 2, + "There is 2 event entries between nine and four days before, inclusive" + ); + + await TrackingDBService.clearAll(); + await db.close(); + Services.prefs.clearUserPref("browser.contentblocking.database.enabled"); +});