Browse Source
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.
5 changed files with 587 additions and 0 deletions
@ -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); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
})(); |
@ -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…
Reference in new issue