summaryrefslogtreecommitdiffstats
path: root/toolkit/xre/test/win/TestLauncherRegistryInfo.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /toolkit/xre/test/win/TestLauncherRegistryInfo.cpp
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/xre/test/win/TestLauncherRegistryInfo.cpp')
-rw-r--r--toolkit/xre/test/win/TestLauncherRegistryInfo.cpp779
1 files changed, 779 insertions, 0 deletions
diff --git a/toolkit/xre/test/win/TestLauncherRegistryInfo.cpp b/toolkit/xre/test/win/TestLauncherRegistryInfo.cpp
new file mode 100644
index 0000000000..273c1cb72a
--- /dev/null
+++ b/toolkit/xre/test/win/TestLauncherRegistryInfo.cpp
@@ -0,0 +1,779 @@
+/* -*- 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";
+
+static std::wstring gBrowserValue;
+static std::wstring gLauncherValue;
+static std::wstring gImageValue;
+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);
+}
+
+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;
+}