summaryrefslogtreecommitdiff
path: root/netwerk/test/mochitests/test_user_agent_updates.html
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/mochitests/test_user_agent_updates.html')
-rw-r--r--netwerk/test/mochitests/test_user_agent_updates.html369
1 files changed, 369 insertions, 0 deletions
diff --git a/netwerk/test/mochitests/test_user_agent_updates.html b/netwerk/test/mochitests/test_user_agent_updates.html
new file mode 100644
index 0000000000..839f9e0005
--- /dev/null
+++ b/netwerk/test/mochitests/test_user_agent_updates.html
@@ -0,0 +1,369 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=897221
+-->
+<head>
+ <title>Test for User Agent Updates</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=897221">Mozilla Bug 897221</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay";
+const PREF_UPDATES = "general.useragent.updates.";
+const PREF_UPDATES_ENABLED = PREF_UPDATES + "enabled";
+const PREF_UPDATES_URL = PREF_UPDATES + "url";
+const PREF_UPDATES_INTERVAL = PREF_UPDATES + "interval";
+const PREF_UPDATES_TIMEOUT = PREF_UPDATES + "timeout";
+
+const DEFAULT_UA = navigator.userAgent;
+const UA_OVERRIDE = "DummyUserAgent";
+const UA_ALT_OVERRIDE = "AltUserAgent";
+
+const UA_PARTIAL_FROM = "\\wozilla"; // /\wozilla
+const UA_PARTIAL_SEP = "#";
+const UA_PARTIAL_TO = UA_OVERRIDE;
+const UA_PARTIAL_OVERRIDE = UA_PARTIAL_FROM + UA_PARTIAL_SEP + UA_PARTIAL_TO;
+const UA_PARTIAL_EXPECTED = DEFAULT_UA.replace(new RegExp(UA_PARTIAL_FROM, 'g'), UA_PARTIAL_TO);
+
+function getUA(host) {
+ var url = location.pathname;
+ url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs';
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false); // sync request
+ xhr.send();
+ is(xhr.status, 200, 'request failed');
+ is(typeof xhr.response, 'string', 'invalid response');
+ return xhr.response;
+}
+
+function testUAIFrame(host, expected, sameQ, message, testNavQ, navSameQ, navMessage, callback) {
+ let url = location.pathname;
+ url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs';
+ let ifr = document.createElement('IFRAME');
+
+ ifr.src = url;
+
+ document.getElementById('content').appendChild(ifr);
+
+ window.addEventListener("message", function recv(e) {
+ ok(sameQ == (e.data.header.indexOf(expected) != -1), message);
+ if (testNavQ) {
+ ok(navSameQ == (e.data.nav.indexOf(expected) != -1), navMessage);
+ }
+ window.removeEventListener("message", recv, false);
+ callback();
+ }, false);
+}
+
+function testUAIFrameNoNav(host, expected, sameQ, message, callback) {
+ testUAIFrame(host, expected, sameQ, message, false, true, '', callback);
+}
+
+const OVERRIDES = [
+ {
+ domain: 'example.org',
+ override: '%DATE%',
+ host: 'http://example.org'
+ },
+ {
+ domain: 'test1.example.org',
+ override: '%PRODUCT%',
+ expected: SpecialPowers.Services.appinfo.name,
+ host: 'http://test1.example.org'
+ },
+ {
+ domain: 'test2.example.org',
+ override: '%APP_ID%',
+ expected: SpecialPowers.Services.appinfo.ID,
+ host: 'http://test2.example.org'
+ },
+ {
+ domain: 'sub1.test1.example.org',
+ override: '%APP_VERSION%',
+ expected: SpecialPowers.Services.appinfo.version,
+ host: 'http://sub1.test1.example.org'
+ },
+ {
+ domain: 'sub2.test1.example.org',
+ override: '%BUILD_ID%',
+ expected: SpecialPowers.Services.appinfo.appBuildID,
+ host: 'http://sub2.test1.example.org'
+ },
+ {
+ domain: 'sub1.test2.example.org',
+ override: '%OS%',
+ expected: SpecialPowers.Services.appinfo.OS,
+ host: 'http://sub1.test2.example.org'
+ },
+ {
+ domain: 'sub2.test2.example.org',
+ override: UA_PARTIAL_OVERRIDE,
+ expected: UA_PARTIAL_EXPECTED,
+ host: 'http://sub2.test2.example.org'
+ },
+];
+
+function getServerURL() {
+ var url = location.pathname;
+ return location.origin + url.slice(0, url.lastIndexOf('/')) + '/user_agent_update.sjs?';
+}
+
+function getUpdateURL() {
+ var url = getServerURL();
+ var overrides = {};
+ overrides[location.hostname] = UA_OVERRIDE;
+ OVERRIDES.forEach(function (val) {
+ overrides[val.domain] = val.override;
+ });
+ url = url + encodeURIComponent(JSON.stringify(overrides)).replace(/%25/g, '%');
+ return url;
+}
+
+function testDownload(callback) {
+ var startTime = Date.now();
+ var url = getUpdateURL();
+ isnot(navigator.userAgent, UA_OVERRIDE, 'UA already overridden');
+ info('Waiting for UA update: ' + url);
+
+ chromeScript.sendAsyncMessage("notify-on-update");
+ SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_UPDATES_ENABLED, true],
+ [PREF_UPDATES_URL, url],
+ [PREF_UPDATES_TIMEOUT, 10000],
+ [PREF_UPDATES_INTERVAL, 1] // 1 second interval
+ ]
+ });
+
+ function waitForUpdate() {
+ info("Update Happened");
+ testUAIFrameNoNav(location.origin, UA_OVERRIDE, true, 'Header UA not overridden', function() {
+ var updateTime = parseInt(getUA('http://example.org'));
+ todo(startTime <= updateTime, 'Update was before start time');
+ todo(updateTime <= Date.now(), 'Update was after present time');
+
+ let overs = OVERRIDES;
+ (function nextOverride() {
+ val = overs.shift();
+ if (val.expected) {
+ testUAIFrameNoNav(val.host, val.expected, true, 'Incorrect URL parameter: ' + val.override, function() {
+ overs.length ? nextOverride() : callback();
+ });
+ } else {
+ nextOverride();
+ }
+ })();
+ });
+ }
+
+ chromeScript.addMessageListener("useragent-update-complete", waitForUpdate);
+}
+
+function testBadUpdate(callback) {
+ var url = getServerURL() + 'invalid-json';
+ var prevOverride = navigator.userAgent;
+ SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_UPDATES_URL, url],
+ [PREF_UPDATES_INTERVAL, 1] // 1 second interval
+ ]
+ }, function () { setTimeout(function () {
+ var ifr = document.createElement('IFRAME');
+ ifr.src = "about:blank";
+
+ ifr.addEventListener('load', function() {
+ // We want to make sure a bad update doesn't cancel out previous
+ // overrides. We do this by waiting for 5 seconds (assuming the update
+ // occurs within 5 seconds), and check that the previous override hasn't
+ // changed.
+ is(navigator.userAgent, prevOverride,
+ 'Invalid update deleted previous override');
+ callback();
+ }, false);
+ document.getElementById('content').appendChild(ifr);
+ }, 5000); });
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("Test sets timeouts to wait for updates to happen.");
+
+SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_APP_UPDATE_TIMERMINIMUMDELAY, 0]
+ ]
+}, function () {
+ chromeScript.sendSyncMessage("UAO-uninit");
+
+ // Sets the OVERRIDES var in the chrome script.
+ // We do this to avoid code duplication.
+ chromeScript.sendSyncMessage("set-overrides", OVERRIDES);
+
+ // testProfileLoad, testDownload, and testProfileSave must run in this order
+ // because testDownload depends on testProfileLoad to call UAO.init()
+ // and testProfileSave depends on testDownload to save overrides to the profile
+ chromeScript.sendAsyncMessage("testProfileLoad", location.hostname);
+});
+
+
+const chromeScript = SpecialPowers.loadChromeScript(_ => {
+ // Enter update timer manager test mode
+ Components.classes["@mozilla.org/updates/timer-manager;1"].getService(
+ Components.interfaces.nsIObserver).observe(null, "utm-test-init", "");
+
+ Components.utils.import("resource://gre/modules/UserAgentOverrides.jsm");
+
+ var _notifyOnUpdate = false;
+
+ var UAO = UserAgentOverrides;
+ UAO.uninit();
+
+ Components.utils.import("resource://gre/modules/FileUtils.jsm");
+ var FU = FileUtils;
+
+ const { TextDecoder, TextEncoder, OS } = Components.utils.import("resource://gre/modules/osfile.jsm");
+ var OSF = OS.File;
+
+ const KEY_PREFDIR = "PrefD";
+ const KEY_APPDIR = "XCurProcD";
+ const FILE_UPDATES = "ua-update.json";
+
+ const UA_OVERRIDE = "DummyUserAgent";
+ const UA_ALT_OVERRIDE = "AltUserAgent";
+
+ const PREF_UPDATES = "general.useragent.updates.";
+ const PREF_UPDATES_ENABLED = PREF_UPDATES + "enabled";
+ const PREF_UPDATES_LASTUPDATED = PREF_UPDATES + "lastupdated";
+
+ Components.utils.import("resource://gre/modules/Services.jsm");
+ Services.prefs.addObserver(PREF_UPDATES_LASTUPDATED, () => {
+ if (_notifyOnUpdate) {
+ _notifyOnUpdate = false; // Only notify once, for the first update.
+ sendAsyncMessage("useragent-update-complete");
+ }
+ } , false);
+
+ var OVERRIDES = null;
+
+ function is(value, expected, message) {
+ sendAsyncMessage("is-message", {value, expected, message});
+ }
+
+ function info(message) {
+ sendAsyncMessage("info-message", message);
+ }
+
+ function testProfileSave(hostname) {
+ info('Waiting for saving to profile');
+ var file = FU.getFile(KEY_PREFDIR, [FILE_UPDATES]).path;
+ (function waitForSave() {
+ OSF.exists(file).then(
+ (exists) => {
+ if (!exists) {
+ setTimeout(waitForSave, 100);
+ return;
+ }
+ return OSF.read(file).then(
+ (bytes) => {
+ info('Saved new overrides');
+ var decoder = new TextDecoder();
+ var overrides = JSON.parse(decoder.decode(bytes));
+ is(overrides[hostname], UA_OVERRIDE, 'Incorrect saved override');
+ OVERRIDES.forEach(function (val) {
+ val.expected && is(overrides[val.domain], val.expected,
+ 'Incorrect saved override: ' + val.override);
+ });
+ sendAsyncMessage("testProfileSaveDone");
+ }
+ );
+ }
+ ).then(null,
+ (reason) => {
+ throw reason
+ }
+ );
+ })();
+ }
+
+ function testProfileLoad(hostname) {
+ var file = FU.getFile(KEY_APPDIR, [FILE_UPDATES]).path;
+ var encoder = new TextEncoder();
+ var overrides = {};
+ overrides[hostname] = UA_ALT_OVERRIDE;
+ var bytes = encoder.encode(JSON.stringify(overrides));
+
+ var badfile = FU.getFile(KEY_PREFDIR, [FILE_UPDATES]).path;
+ var badbytes = encoder.encode("null");
+
+ OSF.writeAtomic(file, bytes, {tmpPath: file + ".tmp"}).then(
+ () => OSF.writeAtomic(badfile, badbytes, {tmpPath: badfile + ".tmp"})
+ ).then(
+ () => {
+ sendAsyncMessage("testProfileLoadDone");
+ },
+ (reason) => {
+ throw reason
+ }
+ );
+ }
+
+
+ addMessageListener("testProfileSave", testProfileSave);
+ addMessageListener("testProfileLoad", testProfileLoad);
+ addMessageListener("set-overrides", function(overrides) { OVERRIDES = overrides});
+ addMessageListener("UAO-init", function() { UAO.init(); });
+ addMessageListener("UAO-uninit", function() { UAO.uninit(); });
+ addMessageListener("notify-on-update", () => { _notifyOnUpdate = true });
+});
+
+chromeScript.addMessageListener("testProfileSaveDone", SimpleTest.finish);
+chromeScript.addMessageListener("testProfileLoadDone", function() {
+ SpecialPowers.pushPrefEnv({
+ set: [[PREF_UPDATES_ENABLED, true]]
+ }, function () {
+ // initialize UserAgentOverrides.jsm and
+ // UserAgentUpdates.jsm and load saved file
+ chromeScript.sendSyncMessage("UAO-init");
+ (function waitForLoad() {
+ var ifr = document.createElement('IFRAME');
+ ifr.src = "about:blank";
+
+ ifr.addEventListener('load', function() {
+ var nav = ifr.contentWindow.navigator;
+ if (nav.userAgent !== UA_ALT_OVERRIDE) {
+ setTimeout(waitForLoad, 100);
+ return;
+ }
+ testUAIFrameNoNav(location.origin, UA_ALT_OVERRIDE, true, 'Did not apply saved override', function () {
+ testDownload(function() {
+ testBadUpdate(function() {
+ chromeScript.sendAsyncMessage("testProfileSave", location.hostname);
+ })
+ })
+ });
+ }, true);
+
+ document.getElementById('content').appendChild(ifr);
+ })();
+ });
+});
+
+chromeScript.addMessageListener("is-message", function(params) {
+ let {value, expected, message} = params;
+ is(value, expected, message);
+});
+chromeScript.addMessageListener("info-message", function(message) {
+ info(message);
+});
+
+</script>
+</pre>
+</body>
+</html>