diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index b18d3c7e7a2..ea3f3034d55 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -306,10 +306,12 @@ endif ifdef MOZ_UPDATER libs:: $(addprefix $(LOCALE_SRCDIR)/,updater/updater.ini) ifeq ($(OS_ARCH),WINNT) - cat $< $(srcdir)/../installer/windows/nsis/updater_append.ini | \ + cat $< $(srcdir)/updater_append.ini $(srcdir)/../installer/windows/nsis/updater_append.ini | \ + sed -e "s/%AB_CD%/$(AB_CD)/" | \ iconv -f UTF-8 -t $(WIN_INSTALLER_CHARSET) > $(FINAL_TARGET)/updater.ini else - $(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET) + cat $< $(srcdir)/updater_append.ini | \ + sed -e "s/%AB_CD%/$(AB_CD)/" > $(FINAL_TARGET)/updater.ini endif endif diff --git a/browser/locales/updater_append.ini b/browser/locales/updater_append.ini new file mode 100644 index 00000000000..d5a9f05ac71 --- /dev/null +++ b/browser/locales/updater_append.ini @@ -0,0 +1,5 @@ + +; IMPORTANT: This file should always start with a newline in case a locale +; provided updater.ini does not end with a newline. +[Installation] +Locale=%AB_CD% diff --git a/toolkit/mozapps/update/src/nsUpdateService.js.in b/toolkit/mozapps/update/src/nsUpdateService.js.in index 58d317e5645..c2e9c2f3e3f 100644 --- a/toolkit/mozapps/update/src/nsUpdateService.js.in +++ b/toolkit/mozapps/update/src/nsUpdateService.js.in @@ -57,7 +57,6 @@ const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details"; const PREF_APP_UPDATE_CHANNEL = "app.update.channel"; const PREF_APP_UPDATE_SHOW_INSTALLED_UI = "app.update.showInstalledUI"; const PREF_APP_UPDATE_LASTUPDATETIME_FMT = "app.update.lastUpdateTime.%ID%"; -const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale"; const PREF_APP_UPDATE_INCOMPATIBLE_MODE = "app.update.incompatible.mode"; const PREF_UPDATE_NEVER_BRANCH = "app.update.never."; const PREF_PARTNER_BRANCH = "app.partner."; @@ -84,6 +83,7 @@ const FILE_UPDATES_DB = "updates.xml"; const FILE_UPDATE_ACTIVE = "active-update.xml"; const FILE_PERMS_TEST = "update.test"; const FILE_LAST_LOG = "last-update.log"; +const FILE_UPDATER_INI = "updater.ini"; const MODE_RDONLY = 0x01; const MODE_WRONLY = 0x02; @@ -122,6 +122,7 @@ const nsIIncrementalDownload = Components.interfaces.nsIIncrementalDownload; const nsIFileInputStream = Components.interfaces.nsIFileInputStream; const nsIFileOutputStream = Components.interfaces.nsIFileOutputStream; const nsICryptoHash = Components.interfaces.nsICryptoHash; +const nsIINIParserFactory = Components.interfaces.nsIINIParserFactory; const Node = Components.interfaces.nsIDOMNode; @@ -129,6 +130,7 @@ var gApp = null; var gPref = null; var gABI = null; var gOSVersion = null; +var gLocale = null; var gConsole = null; var gLogEnabled = { }; @@ -490,20 +492,19 @@ function getPref(func, preference, defaultValue) { } /** - * Gets the current value of the locale. It's possible for this preference to - * be localized, so we have to do a little extra work here. Similar code - * exists in nsHttpHandler.cpp when building the UA string. + * Gets the locale specified by the 'Locale' key in the 'Installation' section + * of updater.ini. */ function getLocale() { - try { - // Get the default branch - var prefs = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefService); - var defaultPrefs = prefs.getDefaultBranch(null); - return defaultPrefs.getCharPref(PREF_GENERAL_USERAGENT_LOCALE); - } catch (e) {} + if (gLocale) + return gLocale; - return gPref.getCharPref(PREF_GENERAL_USERAGENT_LOCALE); + var updaterIni = getFile(KEY_APPDIR, [FILE_UPDATER_INI]); + var iniParser = Components.classes["@mozilla.org/xpcom/ini-parser-factory;1"] + .getService(nsIINIParserFactory).createINIParser(updaterIni); + gLocale = iniParser.getString("Installation", "Locale"); + LOG("General", "Getting Locale from File: " + updaterIni.path + " Locale: " + gLocale); + return gLocale; } /** @@ -1976,7 +1977,7 @@ Checker.prototype = { url = url.replace(/\+/g, "%2B"); if (force) - url += "?force=1" + url += "?force=1" LOG("Checker", "update url: " + url); return url; diff --git a/toolkit/mozapps/update/test/Makefile.in b/toolkit/mozapps/update/test/Makefile.in index 4e447c1f660..9868f076477 100644 --- a/toolkit/mozapps/update/test/Makefile.in +++ b/toolkit/mozapps/update/test/Makefile.in @@ -48,4 +48,13 @@ XPCSHELL_TESTS = \ unit \ $(NULL) +TESTROOT = $(shell cd $(DEPTH) && pwd)/_tests/xpcshell-simple/$(MODULE) + +DEFINES += \ + -DAB_CD=$(AB_CD) \ + $(NULL) + include $(topsrcdir)/config/rules.mk + +libs:: unit/test_0040_general.js.in + $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py -Fsubstitution $(DEFINES) $^ > $(TESTROOT)/unit/test_0040_general.js diff --git a/toolkit/mozapps/update/test/unit/head_update.js b/toolkit/mozapps/update/test/unit/head_update.js index 087b0e02895..ad204d0b462 100644 --- a/toolkit/mozapps/update/test/unit/head_update.js +++ b/toolkit/mozapps/update/test/unit/head_update.js @@ -36,6 +36,9 @@ * ***** END LICENSE BLOCK ***** */ +const NS_APP_USER_PROFILE_50_DIR = "ProfD"; +const NS_APP_PROFILE_DIR_STARTUP = "ProfDS"; + // const Cc, Ci, and Cr are defined in netwerk/test/httpserver/httpd.js so we // need to define unique ones. const AUS_Cc = Components.classes; @@ -90,6 +93,11 @@ function remove_dirs_and_files () { if (file.exists()) file.remove(false); + file = dir.clone(); + file.append("updates.xml"); + if (file.exists()) + file.remove(false); + dir.append("updates"); if (dir.exists()) dir.remove(true); @@ -164,4 +172,39 @@ function createAppInfo(id, name, version, platformVersion) XULAPPINFO_CONTRACTID, XULAppInfoFactory); } +// Use a custom profile dir to keep the bin dir clean... not necessary but nice +var gDirSvc = AUS_Cc["@mozilla.org/file/directory_service;1"]. + getService(AUS_Ci.nsIProperties); +var gTestRoot = gDirSvc.get("CurProcD", AUS_Ci.nsILocalFile); +gTestRoot = gTestRoot.parent.parent; +gTestRoot.append("_tests"); +gTestRoot.append("xpcshell-simple"); +gTestRoot.append("test_update"); +gTestRoot.normalize(); + +// Create and register a profile directory. +var gProfD = gTestRoot.clone(); +gProfD.append("profile"); +if (gProfD.exists()) + gProfD.remove(true); +gProfD.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, 0755); + +var dirProvider = { + getFile: function(prop, persistent) { + persistent.value = true; + if (prop == NS_APP_USER_PROFILE_50_DIR || + prop == NS_APP_PROFILE_DIR_STARTUP) + return gProfD.clone(); + 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(dirProvider); + remove_dirs_and_files(); diff --git a/toolkit/mozapps/update/test/unit/test_0040_general.js.in b/toolkit/mozapps/update/test/unit/test_0040_general.js.in new file mode 100644 index 00000000000..a37b68b04a1 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0040_general.js.in @@ -0,0 +1,307 @@ +/* ***** 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 the Application Update Service. + * + * The Initial Developer of the Original Code is + * Robert Strong . + * + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Mozilla Foundation . All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** + */ + +/* General URL Construction Tests */ + +const DIR_DATA = "data" +const URL_PREFIX = "http://localhost:4444/" + DIR_DATA + "/"; + +const PREF_APP_UPDATE_CHANNEL = "app.update.channel"; +const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override"; +const PREF_PARTNER_BRANCH = "app.partner."; +const PREF_GEN_USERAGENT_LOCALE = "general.useragent.locale"; +const PREF_APP_DISTRIBUTION = "distribution.id"; +const PREF_APP_DISTRIBUTION_VERSION = "distribution.version"; + +var gAppInfo; +var gCheckFunc; +var gInstallationLocale = "@AB_CD@"; + +function run_test() { + do_test_pending(); + startAUS(); + gAppInfo = AUS_Cc["@mozilla.org/xre/app-info;1"] + .getService(AUS_Ci.nsIXULAppInfo) + .QueryInterface(AUS_Ci.nsIXULRuntime); + start_httpserver(DIR_DATA); + do_timeout(0, "run_test_pt1()"); +} + +function end_test() { + do_test_finished(); + stop_httpserver(); +} + +// Helper function for parsing the result from the contructed url +function getResult(url) { + return url.substr(URL_PREFIX.length).split("/")[0]; +} + +// url constructed with %PRODUCT% +function run_test_pt1() { + gCheckFunc = check_test_pt1; + var url = URL_PREFIX + "%PRODUCT%/"; + dump("Testing: url constructed with %PRODUCT% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt1(aResult) { + do_check_eq(aResult, gAppInfo.name); + run_test_pt2(); +} + +// url constructed with %VERSION% +function run_test_pt2() { + gCheckFunc = check_test_pt2; + var url = URL_PREFIX + "%VERSION%/"; + dump("Testing: url constructed with %VERSION% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt2(aResult) { + do_check_eq(aResult, gAppInfo.version); + run_test_pt3(); +} + +// url constructed with %BUILD_ID% +function run_test_pt3() { + gCheckFunc = check_test_pt3; + var url = URL_PREFIX + "%BUILD_ID%/"; + dump("Testing: url constructed with %BUILD_ID% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt3(aResult) { + do_check_eq(aResult, gAppInfo.appBuildID); + run_test_pt4(); +} + +// url constructed with %BUILD_TARGET% +// XXX TODO - it might be nice if we tested the actual ABI +function run_test_pt4() { + gCheckFunc = check_test_pt4; + var url = URL_PREFIX + "%BUILD_TARGET%/"; + dump("Testing: url constructed with %BUILD_TARGET% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt4(aResult) { + try { + abi = gAppInfo.XPCOMABI; + } + catch (e) { + do_throw("nsIXULAppInfo:XPCOMABI not defined\n"); + } + +#ifdef XP_MACOSX + // Mac universal build should report a different ABI than either macppc + // or mactel. This is necessary since nsUpdateService.js will set the ABI to + // Universal-gcc3 for Mac universal builds. + var macutils = AUS_Cc["@mozilla.org/xpcom/mac-utils;1"] + .getService(AUS_Ci.nsIMacUtils); + + if (macutils.isUniversalBinary) + abi = "Universal-gcc3"; +#endif + + do_check_eq(aResult, gAppInfo.OS + "_" + abi); + run_test_pt5(); +} + +// url constructed with %LOCALE% +// Bug 446527 added the locale to the updater.ini +function run_test_pt5() { + gCheckFunc = check_test_pt5; + var url = URL_PREFIX + "%LOCALE%/"; + dump("Testing: url constructed with %LOCALE% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + var defaults = gPrefs.QueryInterface(AUS_Ci.nsIPrefService) + .getDefaultBranch(null); + defaults.setCharPref(PREF_GEN_USERAGENT_LOCALE, "bogus_locale"); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt5(aResult) { + do_check_eq(aResult, gInstallationLocale); + run_test_pt6(); +} + +// url constructed with %CHANNEL% +function run_test_pt6() { + gCheckFunc = check_test_pt6; + var url = URL_PREFIX + "%CHANNEL%/"; + dump("Testing: url constructed with %CHANNEL% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + var defaults = gPrefs.QueryInterface(AUS_Ci.nsIPrefService) + .getDefaultBranch(null); + defaults.setCharPref(PREF_APP_UPDATE_CHANNEL, "bogus_channel"); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt6(aResult) { + do_check_eq(aResult, "bogus_channel"); + run_test_pt7(); +} + +// url constructed with %CHANNEL% with distribution partners +function run_test_pt7() { + gCheckFunc = check_test_pt7; + var url = URL_PREFIX + "%CHANNEL%/"; + dump("Testing: url constructed with %CHANNEL% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + var defaults = gPrefs.QueryInterface(AUS_Ci.nsIPrefService) + .getDefaultBranch(null); + defaults.setCharPref(PREF_PARTNER_BRANCH + "bogus_partner1", "bogus_partner1"); + defaults.setCharPref(PREF_PARTNER_BRANCH + "bogus_partner2", "bogus_partner2"); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt7(aResult) { + do_check_eq(aResult, "bogus_channel-cck-bogus_partner1-bogus_partner2"); + run_test_pt8(); +} + +// url constructed with %PLATFORM_VERSION% +function run_test_pt8() { + gCheckFunc = check_test_pt8; + var url = URL_PREFIX + "%PLATFORM_VERSION%/"; + dump("Testing: url constructed with %PLATFORM_VERSION% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt8(aResult) { + do_check_eq(aResult, gAppInfo.platformVersion); + run_test_pt9(); +} + +// url constructed with %OS_VERSION% +function run_test_pt9() { + gCheckFunc = check_test_pt9; + var url = URL_PREFIX + "%OS_VERSION%/"; + dump("Testing: url constructed with %OS_VERSION% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt9(aResult) { + var osVersion; + var sysInfo = AUS_Cc["@mozilla.org/system-info;1"] + .getService(AUS_Ci.nsIPropertyBag2); + osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version"); + + if (osVersion) { + try { + osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")"; + } + catch (e) { + // Not all platforms have a secondary widget library, so an error is nothing to worry about. + } + osVersion = encodeURIComponent(osVersion); + } + + do_check_eq(aResult, osVersion); + run_test_pt10(); +} + +// url constructed with %DISTRIBUTION% +function run_test_pt10() { + gCheckFunc = check_test_pt10; + var url = URL_PREFIX + "%DISTRIBUTION%/"; + dump("Testing: url constructed with %DISTRIBUTION% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + var defaults = gPrefs.QueryInterface(AUS_Ci.nsIPrefService) + .getDefaultBranch(null); + defaults.setCharPref(PREF_APP_DISTRIBUTION, "bogus_distro"); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt10(aResult) { + do_check_eq(aResult, "bogus_distro"); + run_test_pt11(); +} + +// url constructed with %DISTRIBUTION_VERSION% +function run_test_pt11() { + gCheckFunc = check_test_pt11; + var url = URL_PREFIX + "%DISTRIBUTION_VERSION%/"; + dump("Testing: url constructed with %DISTRIBUTION_VERSION% - " + url + "\n"); + gPrefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url); + var defaults = gPrefs.QueryInterface(AUS_Ci.nsIPrefService) + .getDefaultBranch(null); + defaults.setCharPref(PREF_APP_DISTRIBUTION_VERSION, "bogus_distro_version"); + gUpdateChecker.checkForUpdates(updateCheckListener, true); +} + +function check_test_pt11(aResult) { + do_check_eq(aResult, "bogus_distro_version"); + end_test(); +} + +// Update check listener +const updateCheckListener = { + onProgress: function(request, position, totalSize) { + }, + + onCheckComplete: function(request, updates, updateCount) { + var url = request.channel.originalURI.spec; + dump("onCheckComplete url = " + url + "\n\n"); + var result = getResult(url); + // Use a timeout to allow the XHR to complete + do_timeout(0, "gCheckFunc('" + result + "')"); + }, + + onError: function(request, update) { + var url = request.channel.originalURI.spec; + dump("onError url = " + url + "\n\n"); + var result = getResult(url); + // Use a timeout to allow the XHR to complete + do_timeout(0, "gCheckFunc('" + result + "')"); + }, + + QueryInterface: function(aIID) { + if (!aIID.equals(AUS_Ci.nsIUpdateCheckListener) && + !aIID.equals(AUS_Ci.nsISupports)) + throw AUS_Cr.NS_ERROR_NO_INTERFACE; + return this; + } +};