/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * the Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Robert Strong (Original Author) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ const URL_HOST = "http://localhost:4444/"; const URL_PATH = "data"; var gTestserver; var gXHR; var gXHRCallback; var gCheckFunc; var gResponseBody; var gResponseStatusCode = 200; var gRequestURL; var gUpdateCount; var gUpdates; var gStatusCode; var gStatusText; #include ../shared.js /** * Nulls out the most commonly used global vars used by tests as appropriate. */ function cleanUp() { removeUpdateDirsAndFiles(); // Force the update manager to reload the update data to prevent it from // writing the old data to the files that have just been removed. reloadUpdateManagerData(); // Call app update's observe method passing xpcom-shutdown to test that the // shutdown of app update runs without throwing or leaking. The observer // method is used directly instead of calling notifyObservers so components // outside of the scope of this test don't assert and thereby cause app update // tests to fail. gAUS.observe(null, "xpcom-shutdown", ""); gDirSvc.unregisterProvider(gDirProvider); if (gXHR) { gXHRCallback = null; gXHR.responseXML = null; // null out the event handlers to prevent a mFreeCount leak of 1 gXHR.onerror = null; gXHR.onload = null; gXHR.onprogress = null; gXHR = null; } gTestserver = null; } /** * Sets the most commonly used preferences used by tests */ function setDefaultPrefs() { // Don't display UI for a successful installation. Some apps may not set this // pref to false like Firefox does. gPref.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, false); // Enable Update logging gPref.setBoolPref(PREF_APP_UPDATE_LOG, true); } /** * Initializes the most commonly used settings and creates an instance of the * update service stub. */ function standardInit() { createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1.0", "2.0"); setDefaultPrefs(); // Initialize the update service stub component initUpdateServiceStub(); } /* Custom path handler for the http server */ function pathHandler(metadata, response) { response.setHeader("Content-Type", "text/xml", false); response.setStatusLine(metadata.httpVersion, gResponseStatusCode, "OK"); response.bodyOutputStream.write(gResponseBody, gResponseBody.length); } /** * Launches the updater binary to apply a mar file using the current working * directory for the location to apply the mar. * @param aUpdatesDir * The directory to copy the update mar, binary, etc. * @param aUpdater * The updater binary binary to copy to aUpdatesDir. * @returns The exit value returned from the updater binary. */ function runUpdate(aUpdatesDir, aUpdater) { // Copy the updater binary to the update directory so the updater.ini is not // in the same directory as it is. This prevents the PostUpdate executable // which is defined in the updater.ini from launching and the updater ui from // displaying. aUpdater.copyTo(aUpdatesDir, aUpdater.leafName); var updateBin = aUpdatesDir.clone(); updateBin.append(aUpdater.leafName); if (updateBin.leafName == "updater.app") { updateBin.append("Contents"); updateBin.append("MacOS"); updateBin.append("updater"); if (!updateBin.exists()) do_throw("Unable to find the updater executable!"); } var updatesDirPath = aUpdatesDir.path; if (/ /.test(updatesDirPath)) updatesDirPath = '"' + updatesDirPath + '"'; var cwdPath = do_get_file("/", true).path; if (/ /.test(cwdPath)) cwdPath = '"' + cwdPath + '"'; var process = AUS_Cc["@mozilla.org/process/util;1"]. createInstance(AUS_Ci.nsIProcess); process.init(updateBin); var args = [updatesDirPath, 0, cwdPath]; process.run(true, args, args.length); return process.exitValue; } /** * Sets up the bare bones XMLHttpRequest implementation below. * * @param callback * The callback function that will call the nsIDomEventListener's * handleEvent method. * * Example of the callback function * * function callHandleEvent() { * gXHR.status = gExpectedStatus; * var e = { target: gXHR }; * gXHR.onload.handleEvent(e); * } */ function overrideXHR(callback) { gXHRCallback = callback; gXHR = new xhr(); var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); registrar.registerFactory(gXHR.classID, gXHR.classDescription, gXHR.contractID, gXHR); } /** * Bare bones XMLHttpRequest implementation for testing onprogress, onerror, * and onload nsIDomEventListener handleEvent. */ function xhr() { } xhr.prototype = { overrideMimeType: function(mimetype) { }, setRequestHeader: function(header, value) { }, status: null, channel: { set notificationCallbacks(val) { } }, _url: null, _method: null, open: function (method, url) { gXHR.channel.originalURI = AUS_Cc["@mozilla.org/network/io-service;1"]. getService(AUS_Ci.nsIIOService). newURI(url, null, null); gXHR._method = method; gXHR._url = url; }, responseXML: null, responseText: null, send: function(body) { do_timeout(0, gXHRCallback); // Use a timeout so the XHR completes }, _onprogress: null, set onprogress(val) { gXHR._onprogress = val; }, get onprogress() { return gXHR._onprogress; }, _onerror: null, set onerror(val) { gXHR._onerror = val; }, get onerror() { return gXHR._onerror; }, _onload: null, set onload(val) { gXHR._onload = val; }, get onload() { return gXHR._onload; }, flags: AUS_Ci.nsIClassInfo.SINGLETON, implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT, getHelperForLanguage: function(language) null, getInterfaces: function(count) { var interfaces = [AUS_Ci.nsIXMLHttpRequest, AUS_Ci.nsIJSXMLHttpRequest, AUS_Ci.nsIXMLHttpRequestEventTarget]; count.value = interfaces.length; return interfaces; }, classDescription: "XMLHttpRequest", contractID: "@mozilla.org/xmlextras/xmlhttprequest;1", classID: Components.ID("{c9b37f43-4278-4304-a5e0-600991ab08cb}"), createInstance: function (outer, aIID) { if (outer == null) return gXHR.QueryInterface(aIID); throw AUS_Cr.NS_ERROR_NO_AGGREGATION; }, QueryInterface: function(aIID) { if (aIID.equals(AUS_Ci.nsIXMLHttpRequest) || aIID.equals(AUS_Ci.nsIJSXMLHttpRequest) || aIID.equals(AUS_Ci.nsIXMLHttpRequestEventTarget) || aIID.equals(AUS_Ci.nsIClassInfo) || aIID.equals(AUS_Ci.nsISupports)) return gXHR; throw AUS_Cr.NS_ERROR_NO_INTERFACE; } }; /* Update check listener */ const updateCheckListener = { onProgress: function(request, position, totalSize) { }, onCheckComplete: function(request, updates, updateCount) { gRequestURL = request.channel.originalURI.spec; gUpdateCount = updateCount; gUpdates = updates; dump("onError: url = " + gRequestURL + ", " + "request.status = " + request.status + ", " + "update.statusText = " + request.statusText + ", " + "updateCount = " + updateCount + "\n"); // Use a timeout to allow the XHR to complete do_timeout(0, gCheckFunc); }, onError: function(request, update) { gRequestURL = request.channel.originalURI.spec; gStatusCode = request.status; gStatusText = update.statusText; dump("onError: url = " + gRequestURL + ", " + "request.status = " + gStatusCode + ", " + "update.statusText = " + gStatusText + "\n"); // Use a timeout to allow the XHR to complete do_timeout(0, gCheckFunc); }, QueryInterface: function(aIID) { if (!aIID.equals(AUS_Ci.nsIUpdateCheckListener) && !aIID.equals(AUS_Ci.nsISupports)) throw AUS_Cr.NS_ERROR_NO_INTERFACE; return this; } }; /** * Helper for starting the http server used by the tests * @param aRelativeDirName * The directory name to register relative to * toolkit/mozapps/update/test/unit/ */ function start_httpserver(aRelativeDirName) { var dir = do_get_file(aRelativeDirName); if (!dir.exists()) do_throw("The directory used by nsHttpServer does not exist! path: " + dir.path + "\n"); if (!dir.isDirectory()) do_throw("A file instead of a directory was specified for nsHttpServer " + "registerDirectory! path: " + dir.path + "\n"); do_load_httpd_js(); gTestserver = new nsHttpServer(); gTestserver.registerDirectory("/data/", dir); gTestserver.start(4444); } /* Helper for stopping the http server used by the tests */ function stop_httpserver(callback) { do_check_true(!!callback); gTestserver.stop(callback); } /** * Creates an nsIXULAppInfo * @param id * The ID of the test application * @param name * A name for the test application * @param version * The version of the application * @param platformVersion * The gecko version of the application */ function createAppInfo(id, name, version, platformVersion) { const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"); var XULAppInfo = { vendor: "Mozilla", name: name, ID: id, version: version, appBuildID: "2007010101", platformVersion: platformVersion, platformBuildID: "2007010101", inSafeMode: false, logConsoleErrors: true, OS: "XPCShell", XPCOMABI: "noarch-spidermonkey", QueryInterface: function QueryInterface(iid) { if (iid.equals(AUS_Ci.nsIXULAppInfo) || iid.equals(AUS_Ci.nsIXULRuntime) || iid.equals(AUS_Ci.nsISupports)) return this; throw AUS_Cr.NS_ERROR_NO_INTERFACE; } }; var XULAppInfoFactory = { createInstance: function (outer, iid) { if (outer == null) return XULAppInfo.QueryInterface(iid); throw AUS_Cr.NS_ERROR_NO_AGGREGATION; } }; var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", XULAPPINFO_CONTRACTID, XULAppInfoFactory); } // On Vista XRE_UPDATE_ROOT_DIR can be a directory other than the one in the // application directory. This will reroute it back to the one in the // application directory. var gDirProvider = { getFile: function(prop, persistent) { persistent.value = true; if (prop == XRE_UPDATE_ROOT_DIR) return getCurrentProcessDir(); return null; }, QueryInterface: function(iid) { if (iid.equals(AUS_Ci.nsIDirectoryServiceProvider) || iid.equals(AUS_Ci.nsISupports)) return this; throw AUS_Cr.NS_ERROR_NO_INTERFACE; } }; gDirSvc.QueryInterface(AUS_Ci.nsIDirectoryService).registerProvider(gDirProvider); const INSTALL_LOCALE = "@AB_CD@"; // These are placed at the end so they don't mess up line numbering #ifdef XP_WIN const IS_WIN = true; #else const IS_WIN = false; #endif #ifdef XP_OS2 const IS_OS2 = true; #else const IS_OS2 = false; #endif #ifdef XP_MACOSX const IS_MACOSX = true; #else const IS_MACOSX = false; #endif