783 lines
26 KiB
C++
783 lines
26 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
|
|
|
#define MOZ_USE_LAUNCHER_ERROR
|
|
|
|
#include "mozilla/LauncherRegistryInfo.h"
|
|
#include "mozilla/NativeNt.h"
|
|
#include "mozilla/ScopeExit.h"
|
|
#include "mozilla/Unused.h"
|
|
#include "nsWindowsHelpers.h"
|
|
|
|
#include "LauncherRegistryInfo.cpp"
|
|
|
|
#include <string>
|
|
|
|
static const char kMsgStart[] = "TEST-FAILED | LauncherRegistryInfo | ";
|
|
|
|
static const wchar_t kRegKeyPath[] = L"SOFTWARE\\" EXPAND_STRING_MACRO(
|
|
MOZ_APP_VENDOR) L"\\" EXPAND_STRING_MACRO(MOZ_APP_BASENAME) L"\\Launcher";
|
|
static const wchar_t kBrowserSuffix[] = L"|Browser";
|
|
static const wchar_t kLauncherSuffix[] = L"|Launcher";
|
|
static const wchar_t kImageSuffix[] = L"|Image";
|
|
static const wchar_t kTelemetrySuffix[] = L"|Telemetry";
|
|
|
|
MOZ_RUNINIT static std::wstring gBrowserValue;
|
|
MOZ_RUNINIT static std::wstring gLauncherValue;
|
|
MOZ_RUNINIT static std::wstring gImageValue;
|
|
MOZ_RUNINIT static std::wstring gTelemetryValue;
|
|
|
|
static DWORD gMyImageTimestamp;
|
|
|
|
#define RUN_TEST(result, fn) \
|
|
if ((result = fn()).isErr()) { \
|
|
const mozilla::LauncherError& err = result.inspectErr(); \
|
|
printf("%s%s | %08lx (%s:%d)\n", kMsgStart, #fn, err.mError.AsHResult(), \
|
|
err.mFile, err.mLine); \
|
|
return 1; \
|
|
}
|
|
|
|
#define EXPECT_COMMIT_IS_OK() \
|
|
do { \
|
|
mozilla::LauncherVoidResult vr2 = info.Commit(); \
|
|
if (vr2.isErr()) { \
|
|
return vr2; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_CHECK_RESULT_IS(desired, expected) \
|
|
do { \
|
|
mozilla::LauncherResult<mozilla::LauncherRegistryInfo::ProcessType> \
|
|
result = info.Check(mozilla::LauncherRegistryInfo::desired); \
|
|
if (result.isErr()) { \
|
|
return result.propagateErr(); \
|
|
} \
|
|
if (result.unwrap() != mozilla::LauncherRegistryInfo::expected) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_FAIL); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_ENABLED_STATE_IS(expected) \
|
|
do { \
|
|
mozilla::LauncherResult<mozilla::LauncherRegistryInfo::EnabledState> \
|
|
enabled = info.IsEnabled(); \
|
|
if (enabled.isErr()) { \
|
|
return enabled.propagateErr(); \
|
|
} \
|
|
if (enabled.unwrap() != mozilla::LauncherRegistryInfo::expected) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_TELEMETRY_IS_ENABLED(expected) \
|
|
do { \
|
|
mozilla::LauncherResult<bool> enabled = info.IsTelemetryEnabled(); \
|
|
if (enabled.isErr()) { \
|
|
return enabled.propagateErr(); \
|
|
} \
|
|
if (enabled.unwrap() != expected) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_REG_DWORD_EXISTS_AND_EQ(name, expected) \
|
|
do { \
|
|
mozilla::LauncherResult<mozilla::Maybe<DWORD>> result = \
|
|
ReadRegistryValueData<DWORD>(name, REG_DWORD); \
|
|
if (result.isErr()) { \
|
|
return result.propagateErr(); \
|
|
} \
|
|
if (result.inspect().isNothing() || \
|
|
result.inspect().value() != expected) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_REG_QWORD_EXISTS(name) \
|
|
do { \
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> result = \
|
|
ReadRegistryValueData<uint64_t>(name, REG_QWORD); \
|
|
if (result.isErr()) { \
|
|
return result.propagateErr(); \
|
|
} \
|
|
if (result.inspect().isNothing()) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_REG_QWORD_EXISTS_AND_EQ(name, expected) \
|
|
do { \
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> result = \
|
|
ReadRegistryValueData<uint64_t>(name, REG_QWORD); \
|
|
if (result.isErr()) { \
|
|
return result.propagateErr(); \
|
|
} \
|
|
if (result.inspect().isNothing() || \
|
|
result.inspect().value() != expected) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_REG_DWORD_DOES_NOT_EXIST(name) \
|
|
do { \
|
|
mozilla::LauncherResult<mozilla::Maybe<DWORD>> result = \
|
|
ReadRegistryValueData<DWORD>(name, REG_DWORD); \
|
|
if (result.isErr()) { \
|
|
return result.propagateErr(); \
|
|
} \
|
|
if (result.inspect().isSome()) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_REG_QWORD_DOES_NOT_EXIST(name) \
|
|
do { \
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> result = \
|
|
ReadRegistryValueData<uint64_t>(name, REG_QWORD); \
|
|
if (result.isErr()) { \
|
|
return result.propagateErr(); \
|
|
} \
|
|
if (result.inspect().isSome()) { \
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED); \
|
|
} \
|
|
} while (0)
|
|
|
|
template <typename T>
|
|
static mozilla::LauncherResult<mozilla::Maybe<T>> ReadRegistryValueData(
|
|
const std::wstring& name, DWORD expectedType) {
|
|
T data;
|
|
DWORD dataLen = sizeof(data);
|
|
DWORD type;
|
|
LSTATUS status = ::RegGetValueW(HKEY_CURRENT_USER, kRegKeyPath, name.c_str(),
|
|
RRF_RT_ANY, &type, &data, &dataLen);
|
|
if (status == ERROR_FILE_NOT_FOUND) {
|
|
return mozilla::Maybe<T>();
|
|
}
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
return LAUNCHER_ERROR_FROM_WIN32(status);
|
|
}
|
|
|
|
if (type != expectedType) {
|
|
return LAUNCHER_ERROR_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
|
|
}
|
|
|
|
return mozilla::Some(data);
|
|
}
|
|
|
|
template <typename T>
|
|
static mozilla::LauncherVoidResult WriteRegistryValueData(
|
|
const std::wstring& name, DWORD type, T data) {
|
|
LSTATUS status = ::RegSetKeyValueW(HKEY_CURRENT_USER, kRegKeyPath,
|
|
name.c_str(), type, &data, sizeof(T));
|
|
if (status != ERROR_SUCCESS) {
|
|
return LAUNCHER_ERROR_FROM_WIN32(status);
|
|
}
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult DeleteRegistryValueData(
|
|
const std::wstring& name) {
|
|
LSTATUS status =
|
|
::RegDeleteKeyValueW(HKEY_CURRENT_USER, kRegKeyPath, name.c_str());
|
|
if (status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND) {
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
return LAUNCHER_ERROR_FROM_WIN32(status);
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult DeleteAllRegstryValues() {
|
|
// Unblock commit via ReflectPrefToRegistry
|
|
// (We need to set false, and then true to bypass the early return)
|
|
mozilla::LauncherRegistryInfo info;
|
|
mozilla::LauncherVoidResult vr = info.ReflectPrefToRegistry(false);
|
|
vr = info.ReflectPrefToRegistry(true);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
vr = DeleteRegistryValueData(gImageValue);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
vr = DeleteRegistryValueData(gLauncherValue);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
vr = DeleteRegistryValueData(gBrowserValue);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
return DeleteRegistryValueData(gTelemetryValue);
|
|
}
|
|
|
|
bool GetInstallHash(const char16_t*, mozilla::UniquePtr<NS_tchar[]>& result) {
|
|
return true;
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult SetupEnabledScenario() {
|
|
// Reset the registry state to an enabled state. First, we delete all existing
|
|
// registry values (if any).
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Now we run Check(Launcher)...
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
EXPECT_COMMIT_IS_OK();
|
|
// ...and Check(Browser)
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Browser, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// By this point we are considered to be fully enabled.
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestEmptyRegistry() {
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// LauncherRegistryInfo should have created Launcher and Image values
|
|
EXPECT_REG_DWORD_EXISTS_AND_EQ(gImageValue, gMyImageTimestamp);
|
|
EXPECT_REG_QWORD_EXISTS(gLauncherValue);
|
|
EXPECT_REG_QWORD_DOES_NOT_EXIST(gBrowserValue);
|
|
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestNormal() {
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<DWORD>(gImageValue, REG_DWORD, gMyImageTimestamp);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<uint64_t>(gLauncherValue, REG_QWORD, QPCNowRaw());
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Browser, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// Make sure the browser timestamp is newer than the launcher's
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> launcherTs =
|
|
ReadRegistryValueData<uint64_t>(gLauncherValue, REG_QWORD);
|
|
if (launcherTs.isErr()) {
|
|
return launcherTs.propagateErr();
|
|
}
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> browserTs =
|
|
ReadRegistryValueData<uint64_t>(gBrowserValue, REG_QWORD);
|
|
if (browserTs.isErr()) {
|
|
return browserTs.propagateErr();
|
|
}
|
|
if (launcherTs.inspect().isNothing() || browserTs.inspect().isNothing() ||
|
|
browserTs.inspect().value() <= launcherTs.inspect().value()) {
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_FAIL);
|
|
}
|
|
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::Enabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestBrowserNoLauncher() {
|
|
mozilla::LauncherVoidResult vr = SetupEnabledScenario();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = DeleteRegistryValueData(gLauncherValue);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// Verify that we still don't have a launcher timestamp
|
|
EXPECT_REG_QWORD_DOES_NOT_EXIST(gLauncherValue);
|
|
// Verify that the browser timestamp is now zero
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gBrowserValue, 0ULL);
|
|
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::ForceDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestLauncherNoBrowser() {
|
|
constexpr uint64_t launcherTs = 0x77777777;
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<DWORD>(gImageValue, REG_DWORD, gMyImageTimestamp);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<uint64_t>(gLauncherValue, REG_QWORD, launcherTs);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// Launcher's timestamps is kept intact while browser's is set to 0.
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gLauncherValue, launcherTs);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gBrowserValue, 0ULL);
|
|
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestBrowserLessThanLauncher() {
|
|
constexpr uint64_t launcherTs = 0x77777777, browserTs = 0x66666666;
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<DWORD>(gImageValue, REG_DWORD, gMyImageTimestamp);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<uint64_t>(gLauncherValue, REG_QWORD, launcherTs);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<uint64_t>(gBrowserValue, REG_QWORD, browserTs);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// Launcher's timestamps is kept intact while browser's is set to 0.
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gLauncherValue, launcherTs);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gBrowserValue, 0ULL);
|
|
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestImageTimestampChange() {
|
|
// This should reset the timestamps and then essentially run like
|
|
// TestEmptyRegistry
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<DWORD>(gImageValue, REG_DWORD, 0x12345678);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<uint64_t>(gLauncherValue, REG_QWORD, 1ULL);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<uint64_t>(gBrowserValue, REG_QWORD, 2ULL);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
EXPECT_REG_DWORD_EXISTS_AND_EQ(gImageValue, gMyImageTimestamp);
|
|
EXPECT_REG_QWORD_EXISTS(gLauncherValue);
|
|
EXPECT_REG_QWORD_DOES_NOT_EXIST(gBrowserValue);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestImageTimestampChangeWhenDisabled() {
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<DWORD>(gImageValue, REG_DWORD, 0x12345678);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
vr = WriteRegistryValueData<uint64_t>(gBrowserValue, REG_QWORD, 0ULL);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
EXPECT_REG_DWORD_EXISTS_AND_EQ(gImageValue, gMyImageTimestamp);
|
|
EXPECT_REG_QWORD_DOES_NOT_EXIST(gLauncherValue);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gBrowserValue, 0);
|
|
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::ForceDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestDisableDueToFailure() {
|
|
mozilla::LauncherVoidResult vr = SetupEnabledScenario();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Check that we are indeed enabled.
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::Enabled);
|
|
|
|
// Now call DisableDueToFailure
|
|
mozilla::LauncherVoidResult lvr = info.DisableDueToFailure();
|
|
if (lvr.isErr()) {
|
|
return lvr.propagateErr();
|
|
}
|
|
|
|
// We should now be FailDisabled
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
|
|
// If we delete the launcher timestamp, IsEnabled should then return
|
|
// ForceDisabled.
|
|
vr = DeleteRegistryValueData(gLauncherValue);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::ForceDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestPrefReflection() {
|
|
// Reset the registry to a known good state.
|
|
mozilla::LauncherVoidResult vr = SetupEnabledScenario();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Let's see what happens when we flip the pref to OFF.
|
|
mozilla::LauncherRegistryInfo info;
|
|
mozilla::LauncherVoidResult reflectOk = info.ReflectPrefToRegistry(false);
|
|
if (reflectOk.isErr()) {
|
|
return reflectOk.propagateErr();
|
|
}
|
|
|
|
// Launcher timestamp should be non-existent.
|
|
EXPECT_REG_QWORD_DOES_NOT_EXIST(gLauncherValue);
|
|
// Browser timestamp should be zero
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gBrowserValue, 0ULL);
|
|
// IsEnabled should give us ForceDisabled
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::ForceDisabled);
|
|
|
|
// Now test to see what happens when the pref is set to ON.
|
|
reflectOk = info.ReflectPrefToRegistry(true);
|
|
if (reflectOk.isErr()) {
|
|
return reflectOk.propagateErr();
|
|
}
|
|
|
|
// Launcher and browser timestamps should be non-existent.
|
|
EXPECT_REG_QWORD_DOES_NOT_EXIST(gLauncherValue);
|
|
EXPECT_REG_QWORD_DOES_NOT_EXIST(gBrowserValue);
|
|
|
|
// IsEnabled should give us Enabled.
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::Enabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestTelemetryConfig() {
|
|
mozilla::LauncherVoidResult vr = DeleteAllRegstryValues();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_TELEMETRY_IS_ENABLED(false);
|
|
|
|
mozilla::LauncherVoidResult reflectOk =
|
|
info.ReflectTelemetryPrefToRegistry(false);
|
|
if (reflectOk.isErr()) {
|
|
return reflectOk.propagateErr();
|
|
}
|
|
EXPECT_TELEMETRY_IS_ENABLED(false);
|
|
|
|
reflectOk = info.ReflectTelemetryPrefToRegistry(true);
|
|
if (reflectOk.isErr()) {
|
|
return reflectOk.propagateErr();
|
|
}
|
|
EXPECT_TELEMETRY_IS_ENABLED(true);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestCommitAbort() {
|
|
mozilla::LauncherVoidResult vr = SetupEnabledScenario();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Retrieve the current timestamps to compare later
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> launcherValue =
|
|
ReadRegistryValueData<uint64_t>(gLauncherValue, REG_QWORD);
|
|
if (launcherValue.isErr() || launcherValue.inspect().isNothing()) {
|
|
return launcherValue.propagateErr();
|
|
}
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> browserValue =
|
|
ReadRegistryValueData<uint64_t>(gBrowserValue, REG_QWORD);
|
|
if (browserValue.isErr() || browserValue.inspect().isNothing()) {
|
|
return browserValue.propagateErr();
|
|
}
|
|
uint64_t launcherTs = launcherValue.inspect().value();
|
|
uint64_t browserTs = browserValue.inspect().value();
|
|
|
|
vr = []() -> mozilla::LauncherVoidResult {
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
// No commit
|
|
return mozilla::Ok();
|
|
}();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Exiting the scope discards the change.
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_REG_DWORD_EXISTS_AND_EQ(gImageValue, gMyImageTimestamp);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gLauncherValue, launcherTs);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gBrowserValue, browserTs);
|
|
|
|
// Commit -> Check -> Abort -> Commit
|
|
EXPECT_COMMIT_IS_OK();
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
info.Abort();
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// Nothing is changed.
|
|
EXPECT_REG_DWORD_EXISTS_AND_EQ(gImageValue, gMyImageTimestamp);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gLauncherValue, launcherTs);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gBrowserValue, browserTs);
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::Enabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestDisableDuringLauncherLaunch() {
|
|
mozilla::LauncherVoidResult vr = SetupEnabledScenario();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherResult<mozilla::Maybe<uint64_t>> launcherTs =
|
|
ReadRegistryValueData<uint64_t>(gLauncherValue, REG_QWORD);
|
|
if (launcherTs.isErr()) {
|
|
return launcherTs.propagateErr();
|
|
}
|
|
if (launcherTs.inspect().isNothing()) {
|
|
return LAUNCHER_ERROR_FROM_HRESULT(E_UNEXPECTED);
|
|
}
|
|
|
|
vr = []() -> mozilla::LauncherVoidResult {
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
|
|
// Call DisableDueToFailure with a different instance
|
|
mozilla::LauncherVoidResult vr = []() -> mozilla::LauncherVoidResult {
|
|
mozilla::LauncherRegistryInfo info;
|
|
mozilla::LauncherVoidResult vr = info.DisableDueToFailure();
|
|
if (vr.isErr()) {
|
|
return vr.propagateErr();
|
|
}
|
|
return mozilla::Ok();
|
|
}();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Commit after disable.
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
return mozilla::Ok();
|
|
}();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Make sure we're still FailDisabled and the launcher's timestamp is not
|
|
// updated
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
EXPECT_REG_QWORD_EXISTS_AND_EQ(gLauncherValue, launcherTs.inspect().value());
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestDisableDuringBrowserLaunch() {
|
|
mozilla::LauncherVoidResult vr = SetupEnabledScenario();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
vr = []() -> mozilla::LauncherVoidResult {
|
|
mozilla::LauncherRegistryInfo info;
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Browser, ProcessType::Browser);
|
|
|
|
// Call DisableDueToFailure with a different instance
|
|
mozilla::LauncherVoidResult vr = []() -> mozilla::LauncherVoidResult {
|
|
mozilla::LauncherRegistryInfo info;
|
|
mozilla::LauncherVoidResult vr = info.DisableDueToFailure();
|
|
if (vr.isErr()) {
|
|
return vr.propagateErr();
|
|
}
|
|
return mozilla::Ok();
|
|
}();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Commit after disable.
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
return mozilla::Ok();
|
|
}();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Make sure we're still FailDisabled
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
static mozilla::LauncherVoidResult TestReEnable() {
|
|
mozilla::LauncherVoidResult vr = SetupEnabledScenario();
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Make FailDisabled
|
|
mozilla::LauncherRegistryInfo info;
|
|
vr = info.DisableDueToFailure();
|
|
if (vr.isErr()) {
|
|
return vr.propagateErr();
|
|
}
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
|
|
// Attempt to launch when FailDisabled: Still be FailDisabled
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::FailDisabled);
|
|
|
|
// Change the timestamp
|
|
vr = WriteRegistryValueData<DWORD>(gImageValue, REG_DWORD, 0x12345678);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Attempt to launch again: Launcher comes back
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Launcher);
|
|
EXPECT_COMMIT_IS_OK();
|
|
|
|
// Make ForceDisabled
|
|
vr = info.ReflectPrefToRegistry(false);
|
|
if (vr.isErr()) {
|
|
return vr.propagateErr();
|
|
}
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::ForceDisabled);
|
|
|
|
// Attempt to launch when ForceDisabled: Still be ForceDisabled
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::ForceDisabled);
|
|
|
|
// Change the timestamp
|
|
vr = WriteRegistryValueData<DWORD>(gImageValue, REG_DWORD, 0x12345678);
|
|
if (vr.isErr()) {
|
|
return vr;
|
|
}
|
|
|
|
// Attempt to launch again: Still be ForceDisabled
|
|
EXPECT_CHECK_RESULT_IS(ProcessType::Launcher, ProcessType::Browser);
|
|
EXPECT_COMMIT_IS_OK();
|
|
EXPECT_ENABLED_STATE_IS(EnabledState::ForceDisabled);
|
|
|
|
return mozilla::Ok();
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
auto fullPath = mozilla::GetFullBinaryPath();
|
|
if (!fullPath) {
|
|
return 1;
|
|
}
|
|
|
|
// Global setup for all tests
|
|
gBrowserValue = fullPath.get();
|
|
gBrowserValue += kBrowserSuffix;
|
|
|
|
gLauncherValue = fullPath.get();
|
|
gLauncherValue += kLauncherSuffix;
|
|
|
|
gImageValue = fullPath.get();
|
|
gImageValue += kImageSuffix;
|
|
|
|
gTelemetryValue = fullPath.get();
|
|
gTelemetryValue += kTelemetrySuffix;
|
|
|
|
mozilla::LauncherResult<DWORD> timestamp = 0;
|
|
RUN_TEST(timestamp, GetCurrentImageTimestamp);
|
|
gMyImageTimestamp = timestamp.unwrap();
|
|
|
|
auto onExit = mozilla::MakeScopeExit(
|
|
[]() { mozilla::Unused << DeleteAllRegstryValues(); });
|
|
|
|
mozilla::LauncherVoidResult vr = mozilla::Ok();
|
|
|
|
// All testcases should call SetupEnabledScenario() or
|
|
// DeleteAllRegstryValues() to be order-independent
|
|
RUN_TEST(vr, TestEmptyRegistry);
|
|
RUN_TEST(vr, TestNormal);
|
|
RUN_TEST(vr, TestBrowserNoLauncher);
|
|
RUN_TEST(vr, TestLauncherNoBrowser);
|
|
RUN_TEST(vr, TestBrowserLessThanLauncher);
|
|
RUN_TEST(vr, TestImageTimestampChange);
|
|
RUN_TEST(vr, TestImageTimestampChangeWhenDisabled);
|
|
RUN_TEST(vr, TestDisableDueToFailure);
|
|
RUN_TEST(vr, TestPrefReflection);
|
|
RUN_TEST(vr, TestTelemetryConfig);
|
|
RUN_TEST(vr, TestCommitAbort);
|
|
RUN_TEST(vr, TestDisableDuringLauncherLaunch);
|
|
RUN_TEST(vr, TestDisableDuringBrowserLaunch);
|
|
RUN_TEST(vr, TestReEnable);
|
|
|
|
return 0;
|
|
}
|