1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/test/mochitests/test_user_agent_updates.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,272 @@ 1.4 +<!DOCTYPE HTML> 1.5 +<html> 1.6 +<!-- 1.7 +https://bugzilla.mozilla.org/show_bug.cgi?id=897221 1.8 +--> 1.9 +<head> 1.10 + <title>Test for User Agent Updates</title> 1.11 + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 1.12 + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 1.13 +</head> 1.14 +<body> 1.15 +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=897221">Mozilla Bug 897221</a> 1.16 +<p id="display"></p> 1.17 +<div id="content" style="display: none"></div> 1.18 +<pre id="test"> 1.19 +<script class="testbody" type="text/javascript"> 1.20 + 1.21 +const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay"; 1.22 +const PREF_UPDATES = "general.useragent.updates."; 1.23 +const PREF_UPDATES_ENABLED = PREF_UPDATES + "enabled"; 1.24 +const PREF_UPDATES_URL = PREF_UPDATES + "url"; 1.25 +const PREF_UPDATES_INTERVAL = PREF_UPDATES + "interval"; 1.26 +const PREF_UPDATES_TIMEOUT = PREF_UPDATES + "timeout"; 1.27 + 1.28 +const KEY_PREFDIR = "PrefD"; 1.29 +const KEY_APPDIR = "XCurProcD"; 1.30 +const FILE_UPDATES = "ua-update.json"; 1.31 + 1.32 +const DEFAULT_UA = navigator.userAgent; 1.33 +const UA_OVERRIDE = "DummyUserAgent"; 1.34 +const UA_ALT_OVERRIDE = "AltUserAgent"; 1.35 + 1.36 +const UA_PARTIAL_FROM = "\\wozilla"; // /\wozilla 1.37 +const UA_PARTIAL_SEP = "#"; 1.38 +const UA_PARTIAL_TO = UA_OVERRIDE; 1.39 +const UA_PARTIAL_OVERRIDE = UA_PARTIAL_FROM + UA_PARTIAL_SEP + UA_PARTIAL_TO; 1.40 +const UA_PARTIAL_EXPECTED = DEFAULT_UA.replace(new RegExp(UA_PARTIAL_FROM, 'g'), UA_PARTIAL_TO); 1.41 + 1.42 +function getUA(host) { 1.43 + var url = location.pathname; 1.44 + url = host + url.slice(0, url.lastIndexOf('/')) + '/user_agent.sjs'; 1.45 + 1.46 + var xhr = new XMLHttpRequest(); 1.47 + xhr.open('GET', url, false); // sync request 1.48 + xhr.send(); 1.49 + is(xhr.status, 200, 'request failed'); 1.50 + is(typeof xhr.response, 'string', 'invalid response'); 1.51 + return xhr.response; 1.52 +} 1.53 + 1.54 +const OVERRIDES = [ 1.55 + { 1.56 + domain: 'example.org', 1.57 + override: '%DATE%', 1.58 + host: 'http://example.org' 1.59 + }, 1.60 + { 1.61 + domain: 'test1.example.org', 1.62 + override: '%PRODUCT%', 1.63 + expected: SpecialPowers.Services.appinfo.name, 1.64 + host: 'http://test1.example.org' 1.65 + }, 1.66 + { 1.67 + domain: 'test2.example.org', 1.68 + override: '%APP_ID%', 1.69 + expected: SpecialPowers.Services.appinfo.ID, 1.70 + host: 'http://test2.example.org' 1.71 + }, 1.72 + { 1.73 + domain: 'sub1.test1.example.org', 1.74 + override: '%APP_VERSION%', 1.75 + expected: SpecialPowers.Services.appinfo.version, 1.76 + host: 'http://sub1.test1.example.org' 1.77 + }, 1.78 + { 1.79 + domain: 'sub2.test1.example.org', 1.80 + override: '%BUILD_ID%', 1.81 + expected: SpecialPowers.Services.appinfo.appBuildID, 1.82 + host: 'http://sub2.test1.example.org' 1.83 + }, 1.84 + { 1.85 + domain: 'sub1.test2.example.org', 1.86 + override: '%OS%', 1.87 + expected: SpecialPowers.Services.appinfo.OS, 1.88 + host: 'http://sub1.test2.example.org' 1.89 + }, 1.90 + { 1.91 + domain: 'sub2.test2.example.org', 1.92 + override: UA_PARTIAL_OVERRIDE, 1.93 + expected: UA_PARTIAL_EXPECTED, 1.94 + host: 'http://sub2.test2.example.org' 1.95 + }, 1.96 +]; 1.97 + 1.98 +function getServerURL() { 1.99 + var url = location.pathname; 1.100 + return location.origin + url.slice(0, url.lastIndexOf('/')) + '/user_agent_update.sjs?'; 1.101 +} 1.102 + 1.103 +function getUpdateURL() { 1.104 + var url = getServerURL(); 1.105 + var overrides = {}; 1.106 + overrides[location.hostname] = UA_OVERRIDE; 1.107 + OVERRIDES.forEach(function (val) { 1.108 + overrides[val.domain] = val.override; 1.109 + }); 1.110 + url = url + encodeURIComponent(JSON.stringify(overrides)).replace(/%25/g, '%'); 1.111 + return url; 1.112 +} 1.113 + 1.114 +function testDownload(callback) { 1.115 + var startTime = Date.now(); 1.116 + var url = getUpdateURL(); 1.117 + isnot(navigator.userAgent, UA_OVERRIDE, 'UA already overridden'); 1.118 + info('Waiting for UA update: ' + url); 1.119 + SpecialPowers.pushPrefEnv({ 1.120 + set: [ 1.121 + [PREF_UPDATES_ENABLED, true], 1.122 + [PREF_UPDATES_URL, url], 1.123 + [PREF_UPDATES_TIMEOUT, 10000], 1.124 + [PREF_UPDATES_INTERVAL, 1] // 1 second interval 1.125 + ] 1.126 + }, function waitForUpdate() setTimeout(function () { 1.127 + if (navigator.userAgent !== UA_OVERRIDE) { 1.128 + waitForUpdate(); 1.129 + return; 1.130 + } 1.131 + info('Overrode navigator UA'); 1.132 + is(getUA(location.origin), UA_OVERRIDE, 'Header UA not overridden'); 1.133 + 1.134 + var updateTime = parseInt(getUA('http://example.org')); 1.135 + ok(startTime <= updateTime, 'Update was before start time'); 1.136 + ok(updateTime <= Date.now(), 'Update was after present time'); 1.137 + 1.138 + OVERRIDES.forEach(function (val) { 1.139 + val.expected && is(getUA(val.host), val.expected, 1.140 + 'Incorrect URL parameter: ' + val.override); 1.141 + }); 1.142 + callback(); 1.143 + }, 100)); 1.144 +} 1.145 + 1.146 +function testBadUpdate(callback) { 1.147 + var url = getServerURL() + 'invalid-json'; 1.148 + var prevOverride = navigator.userAgent; 1.149 + SpecialPowers.pushPrefEnv({ 1.150 + set: [ 1.151 + [PREF_UPDATES_URL, url], 1.152 + [PREF_UPDATES_INTERVAL, 1] // 1 second interval 1.153 + ] 1.154 + }, function () setTimeout(function () { 1.155 + // We want to make sure a bad update doesn't cancel out previous overrides. 1.156 + // We do this by waiting for 5 seconds (assuming the update occurs within 5 1.157 + // seconds), and check that the previous override hasn't changed. 1.158 + is(navigator.userAgent, prevOverride, 1.159 + 'Invalid update deleted previous override'); 1.160 + callback(); 1.161 + }, 5000)); 1.162 +} 1.163 + 1.164 +function testProfileLoad(callback) { 1.165 + var file = FU.getFile(KEY_APPDIR, [FILE_UPDATES]).path; 1.166 + var encoder = SpecialPowers.wrap(new TextEncoder()); 1.167 + var overrides = {}; 1.168 + overrides[location.hostname] = UA_ALT_OVERRIDE; 1.169 + var bytes = encoder.encode(JSON.stringify(overrides)); 1.170 + 1.171 + var badfile = FU.getFile(KEY_PREFDIR, [FILE_UPDATES]).path; 1.172 + var badbytes = encoder.encode("null"); 1.173 + 1.174 + OSF.writeAtomic(file, bytes, {tmpPath: file + ".tmp"}).then( 1.175 + () => OSF.writeAtomic(badfile, badbytes, {tmpPath: badfile + ".tmp"}) 1.176 + ).then( 1.177 + () => { 1.178 + SpecialPowers.pushPrefEnv({ 1.179 + set: [[PREF_UPDATES_ENABLED, true]] 1.180 + }, function () { 1.181 + // initialize UserAgentOverrides.jsm and 1.182 + // UserAgentUpdates.jsm and load saved file 1.183 + UAO.init(); 1.184 + (function waitForLoad() { 1.185 + if (navigator.userAgent !== UA_ALT_OVERRIDE) { 1.186 + setTimeout(waitForLoad, 100); 1.187 + return; 1.188 + } 1.189 + is(getUA(location.origin), UA_ALT_OVERRIDE, 'Did not apply saved override'); 1.190 + saveFilePreviousSize = file.fileSize; 1.191 + callback(); 1.192 + })(); 1.193 + }); 1.194 + }, 1.195 + (reason) => { 1.196 + throw reason 1.197 + } 1.198 + ); 1.199 +} 1.200 + 1.201 +function testProfileSave(callback) { 1.202 + info('Waiting for saving to profile'); 1.203 + var file = FU.getFile(KEY_PREFDIR, [FILE_UPDATES]).path; 1.204 + (function waitForSave() { 1.205 + OSF.exists(file).then( 1.206 + (exists) => { 1.207 + if (!exists) { 1.208 + setTimeout(waitForSave, 100); 1.209 + return; 1.210 + } 1.211 + return OSF.read(file).then( 1.212 + (bytes) => { 1.213 + info('Saved new overrides'); 1.214 + var decoder = SpecialPowers.wrap(new TextDecoder()); 1.215 + var overrides = JSON.parse(decoder.decode(bytes)); 1.216 + is(overrides[location.hostname], UA_OVERRIDE, 'Incorrect saved override'); 1.217 + OVERRIDES.forEach(function (val) { 1.218 + val.expected && is(overrides[val.domain], val.expected, 1.219 + 'Incorrect saved override: ' + val.override); 1.220 + }); 1.221 + callback(); 1.222 + } 1.223 + ); 1.224 + } 1.225 + ).then(null, 1.226 + (reason) => { 1.227 + throw reason 1.228 + } 1.229 + ); 1.230 + })(); 1.231 +} 1.232 + 1.233 +SimpleTest.waitForExplicitFinish(); 1.234 + 1.235 +SpecialPowers.Cu.import("resource://gre/modules/FileUtils.jsm", window); 1.236 +var FU = SpecialPowers.wrap(FileUtils); 1.237 + 1.238 +SpecialPowers.Cu.import("resource://gre/modules/osfile.jsm", window); 1.239 +var OSF = SpecialPowers.wrap(OS).File; 1.240 + 1.241 +// Load UserAgentOverrides.jsm after we load update timer manager 1.242 +var UAO = null; 1.243 + 1.244 +var saveFilePreviousSize = 0; 1.245 + 1.246 +SpecialPowers.pushPrefEnv({ 1.247 + set: [ 1.248 + [PREF_APP_UPDATE_TIMERMINIMUMDELAY, 0] 1.249 + ] 1.250 +}, function () { 1.251 + // Enter update timer manager test mode 1.252 + (SpecialPowers.Cc["@mozilla.org/updates/timer-manager;1"].getService( 1.253 + SpecialPowers.Ci.nsIObserver)).observe(null, "utm-test-init", ""); 1.254 + 1.255 + SpecialPowers.Cu.import('resource://gre/modules/UserAgentOverrides.jsm', window); 1.256 + UAO = SpecialPowers.wrap(UserAgentOverrides); 1.257 + UAO.uninit(); 1.258 + 1.259 + // testProfileLoad, testDownload, and testProfileSave must run in this order 1.260 + // because testDownload depends on testProfileLoad to call UAO.init() 1.261 + // and testProfileSave depends on testDownload to save overrides to the profile 1.262 + testProfileLoad(function() 1.263 + testDownload(function() 1.264 + testBadUpdate(function() 1.265 + testProfileSave(SimpleTest.finish) 1.266 + ) 1.267 + ) 1.268 + ); 1.269 +}); 1.270 + 1.271 +</script> 1.272 +</pre> 1.273 +</body> 1.274 +</html> 1.275 +