416 lines
12 KiB
JavaScript
416 lines
12 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
const { UpdateUtils } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/UpdateUtils.sys.mjs"
|
|
);
|
|
const { getAppInfo, updateAppInfo } = ChromeUtils.importESModule(
|
|
"resource://testing-common/AppInfo.sys.mjs"
|
|
);
|
|
const { ctypes } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/ctypes.sys.mjs"
|
|
);
|
|
|
|
ChromeUtils.defineESModuleGetters(this, {
|
|
WindowsRegistry: "resource://gre/modules/WindowsRegistry.sys.mjs",
|
|
});
|
|
|
|
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
|
|
const PREF_APP_PARTNER_BRANCH = "app.partner.";
|
|
const PREF_DISTRIBUTION_ID = "distribution.id";
|
|
const PREF_DISTRIBUTION_VERSION = "distribution.version";
|
|
|
|
const URL_PREFIX = "http://localhost/";
|
|
|
|
const MSG_SHOULD_EQUAL = " should equal the expected value";
|
|
|
|
updateAppInfo();
|
|
const gAppInfo = getAppInfo();
|
|
const gDefaultPrefBranch = Services.prefs.getDefaultBranch(null);
|
|
|
|
function setUpdateChannel(aChannel) {
|
|
gDefaultPrefBranch.unlockPref(PREF_APP_UPDATE_CHANNEL);
|
|
gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, aChannel);
|
|
}
|
|
|
|
function getServicePack() {
|
|
// NOTE: This function is a helper function and not a test. Thus,
|
|
// it uses throw() instead of do_throw(). Any tests that use this function
|
|
// should catch exceptions thrown in this function and deal with them
|
|
// appropriately (usually by calling do_throw).
|
|
const BYTE = ctypes.uint8_t;
|
|
const WORD = ctypes.uint16_t;
|
|
const DWORD = ctypes.uint32_t;
|
|
const WCHAR = ctypes.char16_t;
|
|
const BOOL = ctypes.int;
|
|
|
|
// This structure is described at:
|
|
// http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
|
|
const SZCSDVERSIONLENGTH = 128;
|
|
const OSVERSIONINFOEXW = new ctypes.StructType("OSVERSIONINFOEXW", [
|
|
{ dwOSVersionInfoSize: DWORD },
|
|
{ dwMajorVersion: DWORD },
|
|
{ dwMinorVersion: DWORD },
|
|
{ dwBuildNumber: DWORD },
|
|
{ dwPlatformId: DWORD },
|
|
{ szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH) },
|
|
{ wServicePackMajor: WORD },
|
|
{ wServicePackMinor: WORD },
|
|
{ wSuiteMask: WORD },
|
|
{ wProductType: BYTE },
|
|
{ wReserved: BYTE },
|
|
]);
|
|
|
|
let kernel32 = ctypes.open("kernel32");
|
|
try {
|
|
let GetVersionEx = kernel32.declare(
|
|
"GetVersionExW",
|
|
ctypes.winapi_abi,
|
|
BOOL,
|
|
OSVERSIONINFOEXW.ptr
|
|
);
|
|
let winVer = OSVERSIONINFOEXW();
|
|
winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;
|
|
|
|
if (0 === GetVersionEx(winVer.address())) {
|
|
// Using "throw" instead of "do_throw" (see NOTE above)
|
|
throw new Error("Failure in GetVersionEx (returned 0)");
|
|
}
|
|
|
|
return (
|
|
winVer.wServicePackMajor +
|
|
"." +
|
|
winVer.wServicePackMinor +
|
|
"." +
|
|
winVer.dwBuildNumber
|
|
);
|
|
} finally {
|
|
kernel32.close();
|
|
}
|
|
}
|
|
|
|
function getProcArchitecture() {
|
|
// NOTE: This function is a helper function and not a test. Thus,
|
|
// it uses throw() instead of do_throw(). Any tests that use this function
|
|
// should catch exceptions thrown in this function and deal with them
|
|
// appropriately (usually by calling do_throw).
|
|
const WORD = ctypes.uint16_t;
|
|
const DWORD = ctypes.uint32_t;
|
|
|
|
// This structure is described at:
|
|
// http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
|
|
const SYSTEM_INFO = new ctypes.StructType("SYSTEM_INFO", [
|
|
{ wProcessorArchitecture: WORD },
|
|
{ wReserved: WORD },
|
|
{ dwPageSize: DWORD },
|
|
{ lpMinimumApplicationAddress: ctypes.voidptr_t },
|
|
{ lpMaximumApplicationAddress: ctypes.voidptr_t },
|
|
{ dwActiveProcessorMask: DWORD.ptr },
|
|
{ dwNumberOfProcessors: DWORD },
|
|
{ dwProcessorType: DWORD },
|
|
{ dwAllocationGranularity: DWORD },
|
|
{ wProcessorLevel: WORD },
|
|
{ wProcessorRevision: WORD },
|
|
]);
|
|
|
|
let kernel32 = ctypes.open("kernel32");
|
|
try {
|
|
let GetNativeSystemInfo = kernel32.declare(
|
|
"GetNativeSystemInfo",
|
|
ctypes.winapi_abi,
|
|
ctypes.void_t,
|
|
SYSTEM_INFO.ptr
|
|
);
|
|
let sysInfo = SYSTEM_INFO();
|
|
// Default to unknown
|
|
sysInfo.wProcessorArchitecture = 0xffff;
|
|
|
|
GetNativeSystemInfo(sysInfo.address());
|
|
switch (sysInfo.wProcessorArchitecture) {
|
|
case 12:
|
|
return "aarch64";
|
|
case 9:
|
|
return "x64";
|
|
case 6:
|
|
return "IA64";
|
|
case 0:
|
|
return "x86";
|
|
default:
|
|
// Using "throw" instead of "do_throw" (see NOTE above)
|
|
throw new Error(
|
|
"Unknown architecture returned from GetNativeSystemInfo: " +
|
|
sysInfo.wProcessorArchitecture
|
|
);
|
|
}
|
|
} finally {
|
|
kernel32.close();
|
|
}
|
|
}
|
|
|
|
// Gets the supported CPU instruction set.
|
|
function getInstructionSet() {
|
|
const CPU_EXTENSIONS = [
|
|
"hasSSE4_2",
|
|
"hasSSE4_1",
|
|
"hasSSE4A",
|
|
"hasSSSE3",
|
|
"hasSSE3",
|
|
"hasSSE2",
|
|
"hasSSE",
|
|
"hasMMX",
|
|
"hasNEON",
|
|
"hasARMv7",
|
|
"hasARMv6",
|
|
];
|
|
for (let ext of CPU_EXTENSIONS) {
|
|
if (Services.sysinfo.getProperty(ext)) {
|
|
return ext.substring(3);
|
|
}
|
|
}
|
|
|
|
return "error";
|
|
}
|
|
|
|
// Gets the RAM size in megabytes. This will round the value because sysinfo
|
|
// doesn't always provide RAM in multiples of 1024.
|
|
function getMemoryMB() {
|
|
let memoryMB = "unknown";
|
|
try {
|
|
memoryMB = Services.sysinfo.getProperty("memsize");
|
|
if (memoryMB) {
|
|
memoryMB = Math.round(memoryMB / 1024 / 1024);
|
|
}
|
|
} catch (e) {
|
|
do_throw("Error getting system info memsize property. Exception: " + e);
|
|
}
|
|
return memoryMB;
|
|
}
|
|
|
|
// Helper function for formatting a url and getting the result we're
|
|
// interested in
|
|
async function getResult(url) {
|
|
url = await UpdateUtils.formatUpdateURL(url);
|
|
const component = url.substr(URL_PREFIX.length).split("/")[0];
|
|
// The docs for encodeURIComponent specify that it will encode everything
|
|
// except for:
|
|
// A-Z a-z 0-9 - _ . ! ~ * ' ( )
|
|
// We want to ensure that we are passing Update URL components into
|
|
// encodeURIComponent, so we will make sure that we don't have characters
|
|
// except for these and `%` (for the escape sequences).
|
|
const escapedCharRegex = new RegExp("^[A-Za-z0-9_.!~*'()%-]*$");
|
|
Assert.ok(
|
|
escapedCharRegex.test(component),
|
|
`URL component (${component}) should not have unescaped characters`
|
|
);
|
|
return decodeURIComponent(component);
|
|
}
|
|
|
|
// url constructed with %PRODUCT%
|
|
add_task(async function test_product() {
|
|
let url = URL_PREFIX + "%PRODUCT%/";
|
|
Assert.equal(
|
|
await getResult(url),
|
|
gAppInfo.name,
|
|
"the url param for %PRODUCT%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %VERSION%
|
|
add_task(async function test_version() {
|
|
let url = URL_PREFIX + "%VERSION%/";
|
|
Assert.equal(
|
|
await getResult(url),
|
|
gAppInfo.version,
|
|
"the url param for %VERSION%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %BUILD_ID%
|
|
add_task(async function test_build_id() {
|
|
let url = URL_PREFIX + "%BUILD_ID%/";
|
|
Assert.equal(
|
|
await getResult(url),
|
|
gAppInfo.appBuildID,
|
|
"the url param for %BUILD_ID%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %BUILD_TARGET%
|
|
// XXX TODO - it might be nice if we tested the actual ABI
|
|
add_task(async function test_build_target() {
|
|
let url = URL_PREFIX + "%BUILD_TARGET%/";
|
|
|
|
let abi;
|
|
try {
|
|
abi = gAppInfo.XPCOMABI;
|
|
} catch (e) {
|
|
do_throw("nsIXULAppInfo:XPCOMABI not defined\n");
|
|
}
|
|
|
|
if (AppConstants.platform == "win") {
|
|
// Windows build should report the CPU architecture that it's running on.
|
|
abi += "-" + getProcArchitecture();
|
|
}
|
|
|
|
if (AppConstants.ASAN) {
|
|
// Allow ASan builds to receive their own updates
|
|
abi += "-asan";
|
|
}
|
|
|
|
Assert.equal(
|
|
await getResult(url),
|
|
gAppInfo.OS + "_" + abi,
|
|
"the url param for %BUILD_TARGET%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %LOCALE%
|
|
// Bug 488936 added the update.locale file that stores the update locale
|
|
// Bug 1936528 renamed it as default.locale
|
|
add_task(async function test_locale() {
|
|
// The code that gets the locale accesses the profile which is only available
|
|
// after calling do_get_profile in xpcshell tests. This prevents an error from
|
|
// being logged.
|
|
do_get_profile();
|
|
|
|
let url = URL_PREFIX + "%LOCALE%/";
|
|
Assert.equal(
|
|
await getResult(url),
|
|
"en-US",
|
|
"Assuming we are built with en-US, the url param for %LOCALE%" +
|
|
MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %CHANNEL%
|
|
add_task(async function test_channel() {
|
|
let url = URL_PREFIX + "%CHANNEL%/";
|
|
setUpdateChannel("test_channel");
|
|
Assert.equal(
|
|
await getResult(url),
|
|
"test_channel",
|
|
"the url param for %CHANNEL%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %CHANNEL% with distribution partners
|
|
add_task(async function test_channel_distribution() {
|
|
let url = URL_PREFIX + "%CHANNEL%/";
|
|
gDefaultPrefBranch.setCharPref(
|
|
PREF_APP_PARTNER_BRANCH + "test_partner1",
|
|
"test_partner1"
|
|
);
|
|
gDefaultPrefBranch.setCharPref(
|
|
PREF_APP_PARTNER_BRANCH + "test_partner2",
|
|
"test_partner2"
|
|
);
|
|
Assert.equal(
|
|
await getResult(url),
|
|
"test_channel-cck-test_partner1-test_partner2",
|
|
"the url param for %CHANNEL%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %PLATFORM_VERSION%
|
|
add_task(async function test_platform_version() {
|
|
let url = URL_PREFIX + "%PLATFORM_VERSION%/";
|
|
Assert.equal(
|
|
await getResult(url),
|
|
gAppInfo.platformVersion,
|
|
"the url param for %PLATFORM_VERSION%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %OS_VERSION%
|
|
add_task(async function test_os_version() {
|
|
let url = URL_PREFIX + "%OS_VERSION%/";
|
|
let osVersion =
|
|
Services.sysinfo.getProperty("name") +
|
|
" " +
|
|
Services.sysinfo.getProperty("version");
|
|
|
|
if (AppConstants.platform == "win") {
|
|
try {
|
|
let servicePack = getServicePack();
|
|
osVersion += "." + servicePack;
|
|
} catch (e) {
|
|
do_throw("Failure obtaining service pack: " + e);
|
|
}
|
|
|
|
if (
|
|
Services.vc.compare(Services.sysinfo.getProperty("version"), "10") >= 0
|
|
) {
|
|
const WINDOWS_UBR_KEY_PATH =
|
|
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
|
|
let ubr = WindowsRegistry.readRegKey(
|
|
Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
|
|
WINDOWS_UBR_KEY_PATH,
|
|
"UBR",
|
|
Ci.nsIWindowsRegKey.WOW64_64
|
|
);
|
|
osVersion += ubr !== undefined ? "." + ubr : ".unknown";
|
|
}
|
|
|
|
try {
|
|
osVersion += " (" + getProcArchitecture() + ")";
|
|
} catch (e) {
|
|
do_throw("Failed to obtain processor architecture: " + e);
|
|
}
|
|
}
|
|
|
|
if (osVersion) {
|
|
try {
|
|
osVersion +=
|
|
" (" + Services.sysinfo.getProperty("secondaryLibrary") + ")";
|
|
} catch (e) {
|
|
// Not all platforms have a secondary widget library, so an error is
|
|
// nothing to worry about.
|
|
}
|
|
osVersion = encodeURIComponent(osVersion);
|
|
}
|
|
|
|
Assert.equal(
|
|
await getResult(url),
|
|
osVersion,
|
|
"the url param for %OS_VERSION%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %DISTRIBUTION%
|
|
add_task(async function test_distribution() {
|
|
let url = URL_PREFIX + "%DISTRIBUTION%/";
|
|
gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_ID, "test_distro");
|
|
Assert.equal(
|
|
await getResult(url),
|
|
"test_distro",
|
|
"the url param for %DISTRIBUTION%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %DISTRIBUTION_VERSION%
|
|
add_task(async function test_distribution_version() {
|
|
let url = URL_PREFIX + "%DISTRIBUTION_VERSION%/";
|
|
gDefaultPrefBranch.setCharPref(
|
|
PREF_DISTRIBUTION_VERSION,
|
|
"test_distro_version"
|
|
);
|
|
Assert.equal(
|
|
await getResult(url),
|
|
"test_distro_version",
|
|
"the url param for %DISTRIBUTION_VERSION%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|
|
|
|
// url constructed with %SYSTEM_CAPABILITIES%
|
|
add_task(async function test_systemCapabilities() {
|
|
let url = URL_PREFIX + "%SYSTEM_CAPABILITIES%/";
|
|
let systemCapabilities =
|
|
"ISET:" + getInstructionSet() + ",MEM:" + getMemoryMB();
|
|
Assert.equal(
|
|
await getResult(url),
|
|
systemCapabilities,
|
|
"the url param for %SYSTEM_CAPABILITIES%" + MSG_SHOULD_EQUAL
|
|
);
|
|
});
|