Add opt-out telemetry to the Chrome extension
Privacy policy: https://github.com/Rob--W/pdfjs-telemetry#privacy-policy Unit tests (offline): ``` node test/chromium/test-telemetry.js ``` Server tests (requires that Nginx is installed): ``` git clone https://github.com/Rob--W/pdfjs-telemetry.git cd pdfjs-telemetry/ python testserver.py TestHttp TestHttps ``` Integration test (extension + server): - Build the extension - Edit build/chromium/telemetry.js and remove the check for chrome.runtime.id. - Start Chrome (preferably a new profile): chromium --user-data-dir=/tmp/pdftest --no-first-run - Open chrome://net-internals#events - Visit chrome://extensions and enable Developer mode. - Load unpacked extension, select build/chromium. - Go to the chrome://net-internals tab and filter on pdfjs.robwu.nl. - Click on URL_REQUEST and verify that the server replied with 204. - Reload the extension. - Verify that chrome://net-internals did not contain a new log request.
This commit is contained in:
parent
41f978c7c3
commit
724308c57a
@ -22,3 +22,4 @@ limitations under the License.
|
||||
<script src="pdfHandler-vcros.js"></script>
|
||||
<script src="pageAction/background.js"></script>
|
||||
<script src="suppress-update.js"></script>
|
||||
<script src="telemetry.js"></script>
|
||||
|
@ -88,6 +88,12 @@
|
||||
4
|
||||
],
|
||||
"default": 0
|
||||
},
|
||||
"disableTelemetry": {
|
||||
"title": "Disable telemetry",
|
||||
"type": "boolean",
|
||||
"description": "Whether to prevent the extension from reporting the extension and browser version to the extension developers.",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
162
extensions/chromium/telemetry.js
Normal file
162
extensions/chromium/telemetry.js
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright 2016 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
/* globals chrome, crypto, Headers, Request */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
// This module sends the browser and extension version to a server, to
|
||||
// determine whether it is safe to drop support for old Chrome versions in
|
||||
// future extension updates.
|
||||
//
|
||||
// The source code for the server is available at:
|
||||
// https://github.com/Rob--W/pdfjs-telemetry
|
||||
var LOG_URL = 'https://pdfjs.robwu.nl/logpdfjs';
|
||||
|
||||
// The minimum time to wait before sending a ping, so that we don't send too
|
||||
// many requests even if the user restarts their browser very often.
|
||||
// We want one ping a day, so a minimum delay of 12 hours should be OK.
|
||||
var MINIMUM_TIME_BETWEEN_PING = 12 * 36E5;
|
||||
|
||||
if (chrome.extension.inIncognitoContext) {
|
||||
// The extension uses incognito split mode, so there are two background
|
||||
// pages. Only send telemetry when not in incognito mode.
|
||||
return;
|
||||
}
|
||||
|
||||
if (chrome.runtime.id !== 'oemmndcbldboiebfnladdacbdfmadadm') {
|
||||
// Only send telemetry for the official PDF.js extension.
|
||||
console.warn('Disabled telemetry because this is not an official build.');
|
||||
return;
|
||||
}
|
||||
|
||||
maybeSendPing();
|
||||
setInterval(maybeSendPing, 36E5);
|
||||
|
||||
function maybeSendPing() {
|
||||
getLoggingPref(function(didOptOut) {
|
||||
if (didOptOut) {
|
||||
// Respect the user's decision to not send statistics.
|
||||
return;
|
||||
}
|
||||
if (!navigator.onLine) {
|
||||
// No network available; Wait until the next scheduled ping opportunity.
|
||||
// Even if onLine is true, the server may still be unreachable. But
|
||||
// because it is impossible to tell whether a request failed due to the
|
||||
// inability to connect, or a deliberate connection termination by the
|
||||
// server, we don't validate the response and assume that the request
|
||||
// succeeded. This ensures that the server cannot ask the client to
|
||||
// send more pings.
|
||||
return;
|
||||
}
|
||||
var lastTime = parseInt(localStorage.telemetryLastTime) || 0;
|
||||
var wasUpdated = didUpdateSinceLastCheck();
|
||||
if (!wasUpdated && Date.now() - lastTime < MINIMUM_TIME_BETWEEN_PING) {
|
||||
return;
|
||||
}
|
||||
localStorage.telemetryLastTime = Date.now();
|
||||
|
||||
var deduplication_id = getDeduplicationId(wasUpdated);
|
||||
var extension_version = chrome.runtime.getManifest().version;
|
||||
if (window.Request && 'mode' in Request.prototype) {
|
||||
// fetch is supported in extensions since Chrome 42 (though the above
|
||||
// feature-detection method detects selects Chrome 43+).
|
||||
// Unlike XMLHttpRequest, fetch omits credentials such as cookies in the
|
||||
// requests, which guarantees that the server cannot track the client
|
||||
// via HTTP cookies.
|
||||
fetch(LOG_URL, {
|
||||
method: 'POST',
|
||||
headers: new Headers({
|
||||
'Deduplication-Id': deduplication_id,
|
||||
'Extension-Version': extension_version,
|
||||
}),
|
||||
// Set mode=cors so that the above custom headers are included in the
|
||||
// request.
|
||||
mode: 'cors',
|
||||
});
|
||||
return;
|
||||
}
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('POST', LOG_URL);
|
||||
x.setRequestHeader('Deduplication-Id', deduplication_id);
|
||||
x.setRequestHeader('Extension-Version', extension_version);
|
||||
x.send();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a 40-bit hexadecimal string (=10 letters, 1.1E12 possibilities).
|
||||
* This is used by the server to discard duplicate entries of the same browser
|
||||
* version when the log data is aggregated.
|
||||
*/
|
||||
function getDeduplicationId(wasUpdated) {
|
||||
var id = localStorage.telemetryDeduplicationId;
|
||||
// The ID is only used to deduplicate reports for the same browser version,
|
||||
// so it is OK to change the ID if the browser is updated. By changing the
|
||||
// ID, the server cannot track users for a long period even if it wants to.
|
||||
if (!id || !/^[0-9a-f]{10}$/.test(id) || wasUpdated) {
|
||||
id = '';
|
||||
var buf = new Uint8Array(5);
|
||||
crypto.getRandomValues(buf);
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
var c = buf[i];
|
||||
id += (c >>> 4).toString(16) + (c & 0xF).toString(16);
|
||||
}
|
||||
localStorage.telemetryDeduplicationId = id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the browser has received a major update since the last call
|
||||
* to this function.
|
||||
*/
|
||||
function didUpdateSinceLastCheck() {
|
||||
var chromeVersion = /Chrome\/(\d+)\./.exec(navigator.userAgent);
|
||||
chromeVersion = chromeVersion && chromeVersion[1];
|
||||
if (!chromeVersion || localStorage.telemetryLastVersion === chromeVersion) {
|
||||
return false;
|
||||
}
|
||||
localStorage.telemetryLastVersion = chromeVersion;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the telemetry preference. The callback is invoked with a
|
||||
* boolean if a preference is found, and with the undefined value otherwise.
|
||||
*/
|
||||
function getLoggingPref(callback) {
|
||||
// Try to look up the preference in the storage, in the following order:
|
||||
var areas = ['sync', 'local', 'managed'];
|
||||
|
||||
next();
|
||||
function next(result) {
|
||||
var storageAreaName = areas.shift();
|
||||
if (typeof result === 'boolean' || !storageAreaName) {
|
||||
callback(result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chrome.storage[storageAreaName]) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
chrome.storage[storageAreaName].get('disableTelemetry', function(items) {
|
||||
next(items && items.disableTelemetry);
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
@ -79,6 +79,13 @@ function checkChromePreferencesFile(chromePrefsPath, webPrefsPath) {
|
||||
var webPrefs = JSON.parse(fs.readFileSync(webPrefsPath).toString());
|
||||
var webPrefsKeys = Object.keys(webPrefs);
|
||||
webPrefsKeys.sort();
|
||||
var telemetryIndex = chromePrefsKeys.indexOf('disableTelemetry');
|
||||
if (telemetryIndex >= 0) {
|
||||
chromePrefsKeys.splice(telemetryIndex, 1);
|
||||
} else {
|
||||
console.log('Warning: disableTelemetry key not found in chrome prefs!');
|
||||
return false;
|
||||
}
|
||||
if (webPrefsKeys.length !== chromePrefsKeys.length) {
|
||||
return false;
|
||||
}
|
||||
|
411
test/chromium/test-telemetry.js
Executable file
411
test/chromium/test-telemetry.js
Executable file
@ -0,0 +1,411 @@
|
||||
#!/usr/bin/env node
|
||||
/* Copyright 2016 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
var vm = require('vm');
|
||||
|
||||
var SRC_DIR = __dirname + '/../../';
|
||||
var telemetryJsPath = 'extensions/chromium/telemetry.js';
|
||||
var telemetryJsSource = fs.readFileSync(SRC_DIR + telemetryJsPath);
|
||||
var telemetryScript = new vm.Script(telemetryJsSource, {
|
||||
filename: telemetryJsPath,
|
||||
displayErrors: true,
|
||||
});
|
||||
var LOG_URL = /LOG_URL = '([^']+)'/.exec(telemetryJsSource)[1];
|
||||
|
||||
// Create a minimal extension global that mocks the extension environment that
|
||||
// is used by telemetry.js
|
||||
function createExtensionGlobal() {
|
||||
var window = {};
|
||||
|
||||
// Whenever a "request" was made, the extra headers are appended to this list.
|
||||
var test_requests = window.test_requests = [];
|
||||
|
||||
// Extension API mocks.
|
||||
window.window = window;
|
||||
window.chrome = {};
|
||||
window.chrome.extension = {};
|
||||
window.chrome.extension.inIncognitoContext = false;
|
||||
window.chrome.runtime = {};
|
||||
window.chrome.runtime.id = 'oemmndcbldboiebfnladdacbdfmadadm';
|
||||
window.chrome.runtime.getManifest = function() {
|
||||
return {version: '1.0.0'};
|
||||
};
|
||||
|
||||
function createStorageAPI() {
|
||||
var storageArea = {};
|
||||
storageArea.get = function(key, callback) {
|
||||
assert.equal(key, 'disableTelemetry');
|
||||
// chrome.storage.*. is async, but we make it synchronous to ease testing.
|
||||
callback(storageArea.mock_data);
|
||||
};
|
||||
return storageArea;
|
||||
}
|
||||
window.chrome.storage = {};
|
||||
window.chrome.storage.managed = createStorageAPI();
|
||||
window.chrome.storage.local = createStorageAPI();
|
||||
window.chrome.storage.sync = createStorageAPI();
|
||||
|
||||
// Other DOM.
|
||||
window.navigator = {};
|
||||
window.navigator.onLine = true;
|
||||
window.navigator.userAgent =
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ' +
|
||||
'Chrome/50.0.2661.94 Safari/537.36';
|
||||
window.localStorage = {};
|
||||
|
||||
var getRandomValues_state = 0;
|
||||
window.crypto = {};
|
||||
window.crypto.getRandomValues = function(buf) {
|
||||
var state = getRandomValues_state++;
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
// Totally random byte ;)
|
||||
buf[i] = 0x42 + state;
|
||||
}
|
||||
return buf;
|
||||
};
|
||||
|
||||
// Network-related mocks.
|
||||
window.Request = {};
|
||||
window.Request.prototype = {
|
||||
get mode() { throw new TypeError('Illegal invocation'); },
|
||||
};
|
||||
window.fetch = function(url, options) {
|
||||
assert.equal(url, LOG_URL);
|
||||
assert.equal(options.method, 'POST');
|
||||
assert.equal(options.mode, 'cors');
|
||||
assert.ok(!options.body);
|
||||
test_requests.push(options.headers);
|
||||
};
|
||||
window.Headers = function(headers) {
|
||||
headers = JSON.parse(JSON.stringify(headers)); // Clone.
|
||||
Object.keys(headers).forEach(function(k) {
|
||||
headers[k] = String(headers[k]);
|
||||
});
|
||||
return headers;
|
||||
};
|
||||
window.XMLHttpRequest = function() {
|
||||
var invoked = {
|
||||
open: false,
|
||||
send: false,
|
||||
};
|
||||
var headers = {};
|
||||
return {
|
||||
open: function(method, url) {
|
||||
assert.equal(invoked.open, false);
|
||||
invoked.open = true;
|
||||
assert.equal(method, 'POST');
|
||||
assert.equal(url, LOG_URL);
|
||||
},
|
||||
setRequestHeader: function(k, v) {
|
||||
assert.equal(invoked.open, true);
|
||||
headers[k] = String(v);
|
||||
},
|
||||
send: function(body) {
|
||||
assert.equal(invoked.open, true);
|
||||
assert.equal(invoked.send, false);
|
||||
invoked.send = true;
|
||||
assert.ok(!body);
|
||||
test_requests.push(headers);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// Time-related logic.
|
||||
var timers = [];
|
||||
window.setInterval = function(callback, ms) {
|
||||
assert.equal(typeof callback, 'function');
|
||||
timers.push(callback);
|
||||
};
|
||||
window.Date = {
|
||||
test_now_value: Date.now(),
|
||||
now: function() {
|
||||
return window.Date.test_now_value;
|
||||
},
|
||||
};
|
||||
window.test_fireTimers = function() {
|
||||
assert.ok(timers.length);
|
||||
timers.forEach(function(timer) {
|
||||
timer();
|
||||
});
|
||||
};
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
// Simulate an update of the browser.
|
||||
function updateBrowser(window) {
|
||||
window.navigator.userAgent =
|
||||
window.navigator.userAgent.replace(/Chrome\/(\d+)/, function(_, v) {
|
||||
return 'Chrome/' + (parseInt(v) + 1);
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
function test_first_run() {
|
||||
// Default settings, run extension for the first time.
|
||||
var window = createExtensionGlobal();
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_first_run_incognito() {
|
||||
// The extension should not send any requests when in incognito mode.
|
||||
var window = createExtensionGlobal();
|
||||
window.chrome.extension.inIncognitoContext = true;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, []);
|
||||
},
|
||||
|
||||
function test_storage_managed_unavailable() {
|
||||
var window = createExtensionGlobal();
|
||||
delete window.chrome.storage.managed;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_managed_pref() {
|
||||
var window = createExtensionGlobal();
|
||||
window.chrome.storage.managed.mock_data = {
|
||||
disableTelemetry: true,
|
||||
};
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, []);
|
||||
},
|
||||
|
||||
function test_local_pref() {
|
||||
var window = createExtensionGlobal();
|
||||
window.chrome.storage.local.mock_data = {
|
||||
disableTelemetry: true,
|
||||
};
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, []);
|
||||
},
|
||||
|
||||
function test_managed_pref_is_overridden() {
|
||||
var window = createExtensionGlobal();
|
||||
window.chrome.storage.managed.mock_data = {
|
||||
disableTelemetry: true,
|
||||
};
|
||||
window.chrome.storage.sync.mock_data = {
|
||||
disableTelemetry: false,
|
||||
};
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_run_extension_again() {
|
||||
var window = createExtensionGlobal();
|
||||
telemetryScript.runInNewContext(window);
|
||||
telemetryScript.runInNewContext(window);
|
||||
// Only one request should be sent because of rate-limiting.
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
|
||||
// Simulate that quite some hours passed, but it's still rate-limited.
|
||||
window.Date.test_now_value += 11 * 36E5;
|
||||
telemetryScript.runInNewContext(window);
|
||||
// Only one request should be sent because of rate-limiting.
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
|
||||
// Another hour passes and the request should not be rate-limited any more.
|
||||
window.Date.test_now_value += 1 * 36E5;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}, {
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_running_for_a_while() {
|
||||
var window = createExtensionGlobal();
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
|
||||
// Simulate that the timer fired 11 hours since the last ping. The request
|
||||
// should still be rate-limited.
|
||||
window.Date.test_now_value += 11 * 36E5;
|
||||
window.test_fireTimers();
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
|
||||
// Another hour passes and the request should not be rate-limited any more.
|
||||
window.Date.test_now_value += 1 * 36E5;
|
||||
window.test_fireTimers();
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}, {
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_browser_update() {
|
||||
var window = createExtensionGlobal();
|
||||
telemetryScript.runInNewContext(window);
|
||||
updateBrowser(window);
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}, {
|
||||
// Generate a new ID for better privacy.
|
||||
'Deduplication-Id': '4343434343',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_browser_update_between_pref_toggle() {
|
||||
var window = createExtensionGlobal();
|
||||
telemetryScript.runInNewContext(window);
|
||||
window.chrome.storage.local.mock_data = {
|
||||
disableTelemetry: true,
|
||||
};
|
||||
updateBrowser(window);
|
||||
telemetryScript.runInNewContext(window);
|
||||
window.chrome.storage.local.mock_data = {
|
||||
disableTelemetry: false,
|
||||
};
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}, {
|
||||
// Generate a new ID for better privacy, even if the update happened
|
||||
// while telemetry was disabled.
|
||||
'Deduplication-Id': '4343434343',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_extension_update() {
|
||||
var window = createExtensionGlobal();
|
||||
telemetryScript.runInNewContext(window);
|
||||
window.chrome.runtime.getManifest = function() {
|
||||
return {version: '1.0.1'};
|
||||
};
|
||||
window.Date.test_now_value += 12 * 36E5;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}, {
|
||||
// The ID did not change because the browser version did not change.
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.1',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_unofficial_build() {
|
||||
var window = createExtensionGlobal();
|
||||
var didWarn = false;
|
||||
window.console = {};
|
||||
window.console.warn = function() { didWarn = true; };
|
||||
window.chrome.runtime.id = 'abcdefghijklmnopabcdefghijklmnop';
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, []);
|
||||
assert.ok(didWarn);
|
||||
},
|
||||
|
||||
function test_fetch_is_supported() {
|
||||
var window = createExtensionGlobal();
|
||||
// XMLHttpRequest should not be called when fetch is available. So removing
|
||||
// the XMLHttpRequest API should not change behavior.
|
||||
delete window.XMLHttpRequest;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_fetch_not_supported() {
|
||||
var window = createExtensionGlobal();
|
||||
delete window.fetch;
|
||||
delete window.Request;
|
||||
delete window.Headers;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_fetch_mode_not_supported() {
|
||||
var window = createExtensionGlobal();
|
||||
delete window.Request.prototype.mode;
|
||||
window.fetch = function() { throw new Error('Unexpected call to fetch!'); };
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
|
||||
function test_network_offline() {
|
||||
var window = createExtensionGlobal();
|
||||
// Simulate that the network is down for sure.
|
||||
window.navigator.onLine = false;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, []);
|
||||
|
||||
// Simulate that the network might be up.
|
||||
window.navigator.onLine = true;
|
||||
telemetryScript.runInNewContext(window);
|
||||
assert.deepEqual(window.test_requests, [{
|
||||
'Deduplication-Id': '4242424242',
|
||||
'Extension-Version': '1.0.0',
|
||||
}]);
|
||||
},
|
||||
];
|
||||
var test_i = 0;
|
||||
|
||||
(function next() {
|
||||
var test = tests[test_i++];
|
||||
if (!test) {
|
||||
console.log('All tests completed.');
|
||||
return;
|
||||
}
|
||||
console.log('Running test ' + test_i + '/' + tests.length + ': ' + test.name);
|
||||
test();
|
||||
process.nextTick(next);
|
||||
})();
|
Loading…
x
Reference in New Issue
Block a user