Backed out 2 changesets (bug 1893458, bug 1890634) for causing bustages at TaskbarPinningMetricsTests.cpp. CLOSED TREE

Backed out changeset 29ad5906bfb0 (bug 1890634)
Backed out changeset bfcfe75b775a (bug 1893458)
This commit is contained in:
Butkovits Atila
2024-05-02 00:22:14 +03:00
parent 7c0ffd376f
commit 99d0c239a5
9 changed files with 209 additions and 1355 deletions

View File

@@ -78,105 +78,3 @@ background_update:
- background-update
- metrics
lifetime: application
pinning.windows:
shortcut_created:
type: event
description: >
Event to record when a shortcut is created for the purpose of pinning
to the taskbar on Windows.
extra_keys:
result:
description: >
Readable result of the pinning attempt. Can be: Error,
File Not Found, or Success.
type: string
private_browsing:
description: >
True when the shortcut is for a private browser.
type: boolean
error:
description: >
Present and true when shortcut creation failed for an unknown reason.
type: boolean
success:
description: >
Present and true when shortcut creation succeeded.
type: boolean
file_not_found:
description: >
Present and true when shortcut creation failed due to the file not
being found (NS_ERROR_FILE_NOT_FOUND).
type: boolean
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1890634
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1890634
data_sensitivity:
- interaction
notification_emails:
- install-update@mozilla.com
expires: never
lifetime: ping
pinned_to_taskbar:
type: event
description: >
Event to record when the user pins to the taskbar using Windows 11 APIs,
including if there was an error.
extra_keys:
result:
description: >
Readable result of the pinning attempt. Can be: Not Supported,
Success, Already Pinned, Not Currently Allowed, Error, ErrorLimitedAccessFeatures, or LimitedAccessFeaturesLocked
type: string
not_supported:
description: >
Present and true when Windows 11 pinning is not supported.
type: boolean
success:
description: >
Present and true when Windows 11 pinning succeeded.
type: boolean
already_pinned:
description: >
Present and true when Windows 11 pinning was previously successful.
type: boolean
not_currently_allowed:
description: >
Present and true when Windows 11 pinning is not currently allowed.
type: boolean
error_limited_access_features:
description: >
Present and true when the limited access feature unlock process generated an error.
type: boolean
limited_access_features_locked:
description: >
Present and true when the limited access feature unlock process generated an error.
type: boolean
error:
description: >
Present and true when Windows 11 pinning failed.
type: boolean
private_browsing:
description: >
True when pinning is for private-firefox.
type: boolean
number_of_attempts:
description: >
The number of times that pinning with the taskbar pinning apis was attempted.
type: quantity
fallback_pinning_success:
description: >
Success or Error; valid when using the taskbar pinning api failed and indicates if the fallback to the older mechanism succeeded or not.
type: string
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1890634
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1890634
data_sensitivity:
- interaction
notification_emails:
- install-update@mozilla.com
expires: never
lifetime: ping

View File

@@ -100,18 +100,6 @@ static Result<ComPtr<ITaskbarManager>, HRESULT> InitializeTaskbar() {
return taskbarManager;
}
static bool IsStatusToRetry(Win11PinToTaskBarResultStatus status) {
switch (status) {
case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed:
case Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked:
case Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures:
return true;
default:
return false;
}
}
Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) {
@@ -120,257 +108,229 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
"thread only. It blocks, waiting on things to execute "
"asynchronously on the main thread.");
{
RefPtr<Win11LimitedAccessFeaturesInterface> limitedAccessFeatures =
CreateWin11LimitedAccessFeaturesInterface();
auto result =
limitedAccessFeatures->Unlock(Win11LimitedAccessFeatureType::Taskbar);
if (result.isErr()) {
auto hr = result.unwrapErr();
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar unlock: Error. HRESULT = 0x%lx", hr);
return {hr, Win11PinToTaskBarResultStatus::NotSupported};
}
if (result.unwrap() == false) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar unlock: failed. Not supported on this version of Windows.");
return {S_OK, Win11PinToTaskBarResultStatus::NotSupported};
}
}
HRESULT hr;
Win11PinToTaskBarResultStatus resultStatus =
Win11PinToTaskBarResultStatus::NotSupported;
// Pinning with the Win 11 APIs sometimes reports that pinning is not
// available. There is no documentation on what causes it to not be available
// or why. One way to work around that is to try again. We try 3 times if it's
// not currently available.
const int maxNumberOfRetryAttempts = 3;
int delayInMilliseconds = 200;
int count = 0;
do {
EventWrapper event;
EventWrapper event;
// Everything related to the taskbar and pinning must be done on the main /
// user interface thread or Windows will cause them to fail.
NS_DispatchToMainThread(NS_NewRunnableFunction(
"PinCurrentAppToTaskbarWin11",
[&event, &hr, &resultStatus, aCheckOnly] {
auto CompletedOperations =
[&event, &resultStatus](Win11PinToTaskBarResultStatus status) {
resultStatus = status;
event.Set();
};
// Everything related to the taskbar and pinning must be done on the main /
// user interface thread or Windows will cause them to fail.
NS_DispatchToMainThread(NS_NewRunnableFunction(
"PinCurrentAppToTaskbarWin11", [&event, &hr, &resultStatus, aCheckOnly] {
auto CompletedOperations =
[&event, &resultStatus](Win11PinToTaskBarResultStatus status) {
resultStatus = status;
event.Set();
};
{
RefPtr<Win11LimitedAccessFeaturesInterface> limitedAccessFeatures =
CreateWin11LimitedAccessFeaturesInterface();
auto result = limitedAccessFeatures->Unlock(
Win11LimitedAccessFeatureType::Taskbar);
if (result.isErr()) {
hr = result.unwrapErr();
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar unlock: Error. HRESULT = 0x%lx", hr);
return CompletedOperations(
Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures);
}
auto result = InitializeTaskbar();
if (result.isErr()) {
hr = result.unwrapErr();
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotSupported);
}
if (result.unwrap() == false) {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar unlock: failed. Not supported on "
"this version of Windows.");
return CompletedOperations(
Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked);
}
}
auto result = InitializeTaskbar();
if (result.isErr()) {
hr = result.unwrapErr();
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotSupported);
}
ComPtr<ITaskbarManager> taskbar = result.unwrap();
boolean supported;
hr = taskbar->get_IsSupported(&supported);
if (FAILED(hr) || !supported) {
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: error checking if supported. HRESULT = 0x%lx", hr);
} else {
TASKBAR_PINNING_LOG(LogLevel::Debug, "Taskbar: not supported.");
}
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotSupported);
}
if (aCheckOnly) {
TASKBAR_PINNING_LOG(LogLevel::Debug, "Taskbar: check succeeded.");
return CompletedOperations(Win11PinToTaskBarResultStatus::Success);
}
boolean isAllowed = false;
hr = taskbar->get_IsPinningAllowed(&isAllowed);
if (FAILED(hr) || !isAllowed) {
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: error checking if pinning is allowed. HRESULT = "
"0x%lx",
hr);
} else {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is pinning allowed error or isn't allowed right "
"now. "
"It's not clear when it will be allowed. Possibly after a "
"reboot.");
}
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotCurrentlyAllowed);
}
ComPtr<IAsyncOperation<bool>> isPinnedOperation = nullptr;
hr = taskbar->IsCurrentAppPinnedAsync(&isPinnedOperation);
ComPtr<ITaskbarManager> taskbar = result.unwrap();
boolean supported;
hr = taskbar->get_IsSupported(&supported);
if (FAILED(hr) || !supported) {
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is current app pinned operation failed. HRESULT = "
"Taskbar: error checking if supported. HRESULT = 0x%lx", hr);
} else {
TASKBAR_PINNING_LOG(LogLevel::Debug, "Taskbar: not supported.");
}
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotSupported);
}
if (aCheckOnly) {
TASKBAR_PINNING_LOG(LogLevel::Debug, "Taskbar: check succeeded.");
return CompletedOperations(Win11PinToTaskBarResultStatus::Success);
}
boolean isAllowed = false;
hr = taskbar->get_IsPinningAllowed(&isAllowed);
if (FAILED(hr) || !isAllowed) {
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: error checking if pinning is allowed. HRESULT = "
"0x%lx",
hr);
} else {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is pinning allowed error or isn't allowed right now. "
"It's not clear when it will be allowed. Possibly after a "
"reboot.");
}
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotCurrentlyAllowed);
}
ComPtr<IAsyncOperation<bool>> isPinnedOperation = nullptr;
hr = taskbar->IsCurrentAppPinnedAsync(&isPinnedOperation);
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is current app pinned operation failed. HRESULT = "
"0x%lx",
hr);
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
// Copy the taskbar; don't use it as a reference.
// With the async calls, it's not guaranteed to still be valid
// if sent as a reference.
// resultStatus and event are not defined on the main thread and will
// be alive until the async functions complete, so they can be used as
// references.
auto isPinnedCallback = Callback<IAsyncOperationCompletedHandler<
bool>>([taskbar, &event, &resultStatus, &hr](
IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) mutable -> HRESULT {
auto CompletedOperations =
[&event,
&resultStatus](Win11PinToTaskBarResultStatus status) -> HRESULT {
resultStatus = status;
event.Set();
return S_OK;
};
bool asyncOpSucceeded = status == AsyncStatus::Completed;
if (!asyncOpSucceeded) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is pinned operation failed to complete.");
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
unsigned char isCurrentAppPinned = false;
hr = asyncInfo->GetResults(&isCurrentAppPinned);
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is current app pinned check failed. HRESULT = 0x%lx",
hr);
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
// Copy the taskbar; don't use it as a reference.
// With the async calls, it's not guaranteed to still be valid
// if sent as a reference.
// resultStatus and event are not defined on the main thread and will
// be alive until the async functions complete, so they can be used as
// references.
auto isPinnedCallback = Callback<IAsyncOperationCompletedHandler<
bool>>([taskbar, &event, &resultStatus, &hr](
IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) mutable -> HRESULT {
auto CompletedOperations =
[&event, &resultStatus](
Win11PinToTaskBarResultStatus status) -> HRESULT {
resultStatus = status;
event.Set();
return S_OK;
};
if (isCurrentAppPinned) {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar: current app is already pinned.");
return CompletedOperations(
Win11PinToTaskBarResultStatus::AlreadyPinned);
}
ComPtr<IAsyncOperation<bool>> requestPinOperation = nullptr;
hr = taskbar->RequestPinCurrentAppAsync(&requestPinOperation);
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: request pin current app operation creation failed. "
"HRESULT = 0x%lx",
hr);
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
auto pinAppCallback = Callback<IAsyncOperationCompletedHandler<
bool>>([CompletedOperations, &hr](
IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) -> HRESULT {
bool asyncOpSucceeded = status == AsyncStatus::Completed;
if (!asyncOpSucceeded) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is pinned operation failed to complete.");
"Taskbar: request pin current app operation did not "
"complete.");
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
unsigned char isCurrentAppPinned = false;
hr = asyncInfo->GetResults(&isCurrentAppPinned);
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar: is current app pinned check "
"failed. HRESULT = 0x%lx",
hr);
unsigned char successfullyPinned = 0;
hr = asyncInfo->GetResults(&successfullyPinned);
if (FAILED(hr) || !successfullyPinned) {
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: request pin current app operation failed to pin "
"due to error. HRESULT = 0x%lx",
hr);
} else {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: request pin current app operation failed to pin");
}
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
if (isCurrentAppPinned) {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar: current app is already pinned.");
return CompletedOperations(
Win11PinToTaskBarResultStatus::AlreadyPinned);
}
ComPtr<IAsyncOperation<bool>> requestPinOperation = nullptr;
hr = taskbar->RequestPinCurrentAppAsync(&requestPinOperation);
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: request pin current app operation creation failed. "
"HRESULT = 0x%lx",
hr);
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
auto pinAppCallback = Callback<
IAsyncOperationCompletedHandler<bool>>(
[CompletedOperations, &hr](IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) -> HRESULT {
bool asyncOpSucceeded = status == AsyncStatus::Completed;
if (!asyncOpSucceeded) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: request pin current app operation did not "
"complete.");
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
unsigned char successfullyPinned = 0;
hr = asyncInfo->GetResults(&successfullyPinned);
if (FAILED(hr) || !successfullyPinned) {
if (FAILED(hr)) {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar: request pin current app "
"operation failed to pin "
"due to error. HRESULT = 0x%lx",
hr);
} else {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar: request pin current app "
"operation failed to pin");
}
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: request pin current app operation succeeded");
return CompletedOperations(
Win11PinToTaskBarResultStatus::Success);
});
HRESULT pinOperationHR =
requestPinOperation->put_Completed(pinAppCallback.Get());
if (FAILED(pinOperationHR)) {
TASKBAR_PINNING_LOG(LogLevel::Debug,
"Taskbar: request pin operation failed when "
"setting completion "
"callback. HRESULT = 0x%lx",
hr);
hr = pinOperationHR;
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
// DO NOT SET event HERE. It will be set in the pin operation
// callback As in, operations are not completed, so don't call
// CompletedOperations
return S_OK;
});
HRESULT isPinnedOperationHR =
isPinnedOperation->put_Completed(isPinnedCallback.Get());
if (FAILED(isPinnedOperationHR)) {
hr = isPinnedOperationHR;
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is pinned operation failed when setting completion "
"Taskbar: request pin current app operation succeeded");
return CompletedOperations(Win11PinToTaskBarResultStatus::Success);
});
HRESULT pinOperationHR =
requestPinOperation->put_Completed(pinAppCallback.Get());
if (FAILED(pinOperationHR)) {
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: request pin operation failed when setting completion "
"callback. HRESULT = 0x%lx",
hr);
hr = pinOperationHR;
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
// DO NOT SET event HERE. It will be set in the is pin operation
// callback. As in, operations are not completed, so don't call
// DO NOT SET event HERE. It will be set in the pin operation
// callback As in, operations are not completed, so don't call
// CompletedOperations
}));
return S_OK;
});
// block until the pinning is completed on the main thread
event.Wait();
HRESULT isPinnedOperationHR =
isPinnedOperation->put_Completed(isPinnedCallback.Get());
if (FAILED(isPinnedOperationHR)) {
hr = isPinnedOperationHR;
TASKBAR_PINNING_LOG(
LogLevel::Debug,
"Taskbar: is pinned operation failed when setting completion "
"callback. HRESULT = 0x%lx",
hr);
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
count++;
if (!IsStatusToRetry(resultStatus) || (count >= maxNumberOfRetryAttempts)) {
break;
}
// DO NOT SET event HERE. It will be set in the is pin operation
// callback As in, operations are not completed, so don't call
// CompletedOperations
}));
// If retrying, put in a delay. Make it short the first time and slightly
// longer the second time. This is not on the main thread so shouldn't
// forcefully block the user. If called from Javascript with an await it
// will still block, but that's a decision on the Javascript side
Sleep(delayInMilliseconds);
delayInMilliseconds *= 2;
} while (count < maxNumberOfRetryAttempts);
// block until the pinning is completed on the main thread
event.Wait();
return {hr, resultStatus, count};
return {hr, resultStatus};
}
#else // MINGW32 implementation below

View File

@@ -14,17 +14,18 @@
#include "nsString.h"
#include <wrl.h>
#include <windows.h> // for HRESULT
#include <mozilla/DefineEnum.h>
MOZ_DEFINE_ENUM_CLASS(Win11PinToTaskBarResultStatus,
(Failed, NotCurrentlyAllowed, AlreadyPinned, Success,
NotSupported, ErrorLimitedAccessFeatures,
LimitedAccessFeaturesLocked));
enum class Win11PinToTaskBarResultStatus {
Failed,
NotCurrentlyAllowed,
AlreadyPinned,
Success,
NotSupported,
};
struct Win11PinToTaskBarResult {
HRESULT errorCode;
Win11PinToTaskBarResultStatus result;
int numAttempts;
};
Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(

View File

@@ -1,713 +0,0 @@
/* -*- 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 http://mozilla.org/MPL/2.0/. */
#include "nsWindowsShellServiceInternal.h"
#include "gtest/gtest.h"
#include "gtest/FOGFixture.h"
#include "mozilla/glean/fog_ffi_generated.h"
#include <iostream>
using namespace mozilla;
using namespace mozilla::glean::impl;
using namespace mozilla::glean::pinning_windows;
namespace telemetry_event {
template <typename event_type>
bool IsValidButEmpty(const event_type& event) {
auto value = event.TestGetValue();
if (!value.isOk()) {
return false;
}
if (value.unwrap().isSome()) {
return false;
}
return true;
}
template <typename event_type>
bool CountsMatch(const event_type& event, size_t count) {
auto value = event.TestGetValue();
if (!value.isOk()) {
return false;
}
auto unwrapped = value.unwrap();
if (!unwrapped.isSome()) {
return false;
}
if (unwrapped.ref().Length() != count) {
return false;
}
return true;
}
} // namespace telemetry_event
template <typename event_extra_type>
static std::map<nsCString, nsCString> CreateKeyValuePairs(
const event_extra_type& eventExtras) {
auto serializedExtras = eventExtras.ToFfiExtra();
auto keys = std::move(std::get<0>(serializedExtras));
auto values = std::move(std::get<1>(serializedExtras));
if (keys.Length() != values.Length()) {
MOZ_ASSERT(false);
return std::map<nsCString, nsCString>();
}
std::map<nsCString, nsCString> result;
for (size_t i = 0; i < keys.Length(); i++) {
result[keys[i]] = values[i];
}
return result;
}
template <typename extra_type>
bool IsEqual(const extra_type& control,
mozilla::glean::impl::RecordedEvent& event) {
// generate a map from the control data
std::map<nsCString, nsCString> controlMap = CreateKeyValuePairs(control);
if (controlMap.size() != event.mExtra.Length()) {
return false;
}
// now walk through the event data and check
for (size_t i = 0; i < event.mExtra.Length(); i++) {
const auto& key = std::get<0>(event.mExtra[i]);
const auto& value = std::get<1>(event.mExtra[i]);
auto iterator = controlMap.find(key);
if (iterator == controlMap.end()) {
return false;
}
if (iterator->second != value) {
return false;
}
}
return true;
}
template <typename extra_type>
bool IsEqual(const extra_type& control, const extra_type& generated) {
std::map<nsCString, nsCString> controlMap = CreateKeyValuePairs(control);
std::map<nsCString, nsCString> generatedMap = CreateKeyValuePairs(generated);
if (controlMap.size() != generatedMap.size()) {
return false;
}
for (auto i : controlMap) {
auto found = generatedMap.find(i.first);
if (found == generatedMap.end()) {
return false;
}
if (found->second != i.second) {
return false;
}
}
return true;
}
class WindowsPinningShortcutTestFixture : public FOGFixture {};
MOZ_DEFINE_ENUM_CLASS(PinningShortcutOperation,
(Succeed, FailFileNotFound, FailError, FailEmptyOnFind));
static const char* EnumName(PinningShortcutOperation operation) {
switch (operation) {
case PinningShortcutOperation::Succeed:
return "PinningShortcutOperation::Succeed";
case PinningShortcutOperation::FailFileNotFound:
return "PinningShortcutOperation::FailFileNotFound";
case PinningShortcutOperation::FailError:
return "PinningShortcutOperation::FailError";
case PinningShortcutOperation::FailEmptyOnFind:
return "PinningShortcutOperation::FailEmptyOnFind";
default:
MOZ_ASSERT(false);
return "PinningShortcutOperation::UNDEFINED";
}
}
MOZ_DEFINE_ENUM_CLASS(PinningFallbackOperation, (Succeed, Fail));
static const char* EnumName(PinningFallbackOperation operation) {
switch (operation) {
case PinningFallbackOperation::Succeed:
return "PinningFallbackOperation::Succeed";
case PinningFallbackOperation::Fail:
return "PinningFallbackOperation::Fail";
default:
MOZ_ASSERT(false);
return "PinningFallbackOperation::UNDEFINED";
}
}
static const char* EnumName(Win11PinToTaskBarResultStatus operation) {
switch (operation) {
case Win11PinToTaskBarResultStatus::Success:
return "Win11PinToTaskBarResultStatus::Success";
case Win11PinToTaskBarResultStatus::Failed:
return "Win11PinToTaskBarResultStatus::Failed";
case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed:
return "Win11PinToTaskBarResultStatus::NotCurrentlyAllowed";
case Win11PinToTaskBarResultStatus::AlreadyPinned:
return "Win11PinToTaskBarResultStatus::AlreadyPinned";
case Win11PinToTaskBarResultStatus::NotSupported:
return "Win11PinToTaskBarResultStatus::NotSupported";
case Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures:
return "Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures";
case Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked:
return "Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked";
default:
MOZ_ASSERT(false);
return "Win11PinToTaskBarResultStatus::UNDEFINED";
}
}
/**
* Mock version of PinCurrentAppToTaskbarHelper.
*
* Takes the values to return from the methods and returns them
* to mock results for testing telemetry events are generated
* properly by PinCurrentAppToTaskbarImpl.
*/
class PinCurrentAppToTaskbarHelperMetricsTesting
: public PinCurrentAppToTaskbarHelper {
public:
PinCurrentAppToTaskbarHelperMetricsTesting(
PinningShortcutOperation shortcutOperation,
Win11PinToTaskBarResultStatus apiOperation,
PinningFallbackOperation fallbackOperation);
void CheckNotMainThread() override {}
mozilla::Result<bool, nsresult> CreateShortcutForTaskbar(
bool aCheckOnly, bool aPrivateBrowsing, const nsAString& aAppUserModelId,
const nsAString& aShortcutName, const nsAString& aShortcutSubstring,
nsIFile* aShortcutsLogDir, nsIFile* aGreDir, nsIFile* aProgramsDir,
nsAutoString& aShortcutPath) override;
Win11PinToTaskBarResult PinCurrentAppViaAPI(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) override;
nsresult PinCurrentAppFallback(bool aCheckOnly,
const nsAString& aAppUserModelId,
const nsAString& aShortcutPath) override;
private:
PinningShortcutOperation mShortcutOperation;
Win11PinToTaskBarResultStatus mApiOperation;
PinningFallbackOperation mFallbackOperation;
};
inline PinCurrentAppToTaskbarHelperMetricsTesting::
PinCurrentAppToTaskbarHelperMetricsTesting(
PinningShortcutOperation shortcutOperation,
Win11PinToTaskBarResultStatus apiOperation,
PinningFallbackOperation fallbackOperation)
: mShortcutOperation(shortcutOperation),
mApiOperation(apiOperation),
mFallbackOperation(fallbackOperation) {}
inline mozilla::Result<bool, nsresult>
PinCurrentAppToTaskbarHelperMetricsTesting::CreateShortcutForTaskbar(
bool aCheckOnly, bool aPrivateBrowsing, const nsAString& aAppUserModelId,
const nsAString& aShortcutName, const nsAString& aShortcutSubstring,
nsIFile* aShortcutsLogDir, nsIFile* aGreDir, nsIFile* aProgramsDir,
nsAutoString& aShortcutPath) {
using namespace mozilla;
switch (mShortcutOperation) {
case PinningShortcutOperation::Succeed:
return true;
case PinningShortcutOperation::FailFileNotFound:
return Err(NS_ERROR_FILE_NOT_FOUND);
case PinningShortcutOperation::FailError:
return Err(NS_ERROR_FAILURE);
case PinningShortcutOperation::FailEmptyOnFind:
return false;
default:
MOZ_ASSERT(false);
return Err(NS_ERROR_FAILURE);
}
}
inline Win11PinToTaskBarResult
PinCurrentAppToTaskbarHelperMetricsTesting::PinCurrentAppViaAPI(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) {
const int numAttempts = 1;
return {S_OK, mApiOperation, numAttempts};
}
inline nsresult
PinCurrentAppToTaskbarHelperMetricsTesting::PinCurrentAppFallback(
bool aCheckOnly, const nsAString& aAppUserModelId,
const nsAString& aShortcutPath) {
switch (mFallbackOperation) {
case PinningFallbackOperation::Fail:
return NS_ERROR_FAILURE;
case PinningFallbackOperation::Succeed:
return NS_OK;
default:
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
}
static void TestPinning(bool aCheckOnly,
PinningShortcutOperation shortcutOperation,
Win11PinToTaskBarResultStatus apiOperation,
PinningFallbackOperation fallbackOperation,
bool privateBrowsing = false) {
UniquePtr<PinCurrentAppToTaskbarHelper> helper(
new PinCurrentAppToTaskbarHelperMetricsTesting(
shortcutOperation, apiOperation, fallbackOperation));
auto appUserModelId = u""_ns;
auto shortcutName = u""_ns;
auto shortcutSubstring = u""_ns;
nsIFile* shortcutsLogDir = nullptr;
nsIFile* greDir = nullptr;
nsIFile* programsDir = nullptr;
PinCurrentAppToTaskbarImpl(aCheckOnly, privateBrowsing, appUserModelId,
shortcutName, shortcutSubstring, shortcutsLogDir,
greDir, programsDir, std::move(helper));
}
struct ShortcutTestCase {
PinningShortcutOperation operation;
nsresult expectedResult;
ShortcutCreatedExtra expectedExtras;
friend void PrintTo(const ShortcutTestCase& testCase, std::ostream* os) {
*os << "(With operation " << EnumName(testCase.operation)
<< ", expected result event text == " << int(testCase.expectedResult)
<< " and expectedExtras with result text == "
<< testCase.expectedExtras.result << ")";
}
};
class WindowsPinningShortcuts : public FOGFixtureWithParam<ShortcutTestCase> {};
TEST_P(
WindowsPinningShortcuts,
WindowsPinningTestShortcutTelemetryEventCreationCheckOnlyPrivateBrowsingOn) {
auto testCase = GetParam();
const bool checkOnly = true;
const bool privateBrowsing = true;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(checkOnly, testCase.operation,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
EXPECT_TRUE(telemetry_event::IsValidButEmpty(shortcut_created));
}
TEST_P(
WindowsPinningShortcuts,
WindowsPinningTestShortcutTelemetryEventCreationCheckOnlyPrivateBrowsingOff) {
auto testCase = GetParam();
const bool checkOnly = true;
const bool privateBrowsing = false;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(checkOnly, testCase.operation,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
EXPECT_TRUE(telemetry_event::IsValidButEmpty(shortcut_created));
}
TEST_P(WindowsPinningShortcuts,
WindowsPinningTestShortcutTelemetryEventCreationPrivateBrowsingOn) {
auto testCase = GetParam();
const bool doFullPinningFlow = false;
const bool privateBrowsing = true;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(doFullPinningFlow, testCase.operation,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
auto extras = telemetry::shortcut::CreateEventExtra(testCase.expectedResult,
privateBrowsing);
// confirm that the event extras creation works as expected
EXPECT_TRUE(IsEqual(testCase.expectedExtras, extras));
size_t one = 1;
EXPECT_TRUE(telemetry_event::CountsMatch(shortcut_created, one));
auto metricsEvents = shortcut_created.TestGetValue().unwrap().ref();
auto control = testCase.expectedExtras;
EXPECT_TRUE(IsEqual(control, metricsEvents[0]));
}
TEST_P(WindowsPinningShortcuts,
WindowsPinningTestShortcutTelemetryEventCreationPrivateBrowsingOff) {
auto testCase = GetParam();
const bool doFullPinningFlow = false;
const bool privateBrowsing = false;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(doFullPinningFlow, testCase.operation,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
auto extras = telemetry::shortcut::CreateEventExtra(testCase.expectedResult,
privateBrowsing);
// confirm that the event extras creation works as expected
EXPECT_TRUE(IsEqual(testCase.expectedExtras, extras));
size_t one = 1;
EXPECT_TRUE(telemetry_event::CountsMatch(shortcut_created, one));
auto metricsEvents = shortcut_created.TestGetValue().unwrap().ref();
auto control = testCase.expectedExtras;
EXPECT_TRUE(IsEqual(control, metricsEvents[0]));
}
static const ShortcutTestCase shortcutTestCases[] = {
{.operation = PinningShortcutOperation::FailFileNotFound,
.expectedResult = NS_ERROR_FILE_NOT_FOUND,
.expectedExtras = {.fileNotFound = Some(true),
.privateBrowsing = Some(false),
.result = Some(
telemetry::shortcut::TELEMETRY_FILE_NOT_FOUND)}},
{.operation = PinningShortcutOperation::FailError,
.expectedResult = NS_ERROR_FAILURE,
.expectedExtras = {.error = Some(true),
.privateBrowsing = Some(false),
.result = Some(telemetry::shortcut::TELEMETRY_ERROR)}},
{.operation = PinningShortcutOperation::Succeed,
.expectedResult = NS_OK,
.expectedExtras = {.privateBrowsing = Some(false),
.result = Some(telemetry::shortcut::TELEMETRY_SUCCESS),
.success = Some(true)}},
};
INSTANTIATE_TEST_SUITE_P(WindowsPinningShortcutTelemetryTests,
WindowsPinningShortcuts,
::testing::ValuesIn(shortcutTestCases));
TEST_F(WindowsPinningShortcutTestFixture,
TestShortcutFailOnEmptyFindPrivateBrowsingOn) {
const bool privateBrowsing = true;
// special case FailEmptyOnFind. That should not generate an event at all
TestPinning(true, PinningShortcutOperation::FailEmptyOnFind,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
EXPECT_TRUE(telemetry_event::IsValidButEmpty(shortcut_created));
TestResetFOG();
TestPinning(false, PinningShortcutOperation::FailEmptyOnFind,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
EXPECT_TRUE(telemetry_event::IsValidButEmpty(shortcut_created));
}
TEST_F(WindowsPinningShortcutTestFixture,
TestShortcutFailOnEmptyFindPrivateBrowsingOff) {
const bool privateBrowsing = false;
// special case FailEmptyOnFind. That should not generate an event at all
TestPinning(true, PinningShortcutOperation::FailEmptyOnFind,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
EXPECT_TRUE(telemetry_event::IsValidButEmpty(shortcut_created));
TestResetFOG();
TestPinning(false, PinningShortcutOperation::FailEmptyOnFind,
Win11PinToTaskBarResultStatus::Success,
PinningFallbackOperation::Succeed, privateBrowsing);
EXPECT_TRUE(telemetry_event::IsValidButEmpty(shortcut_created));
}
struct PinningAPITestCase {
Win11PinToTaskBarResultStatus result;
PinnedToTaskbarExtra expectedExtras;
friend void PrintTo(const PinningAPITestCase& testCase, std::ostream* os) {
*os << "(For pinning api operation == " << EnumName(testCase.result)
<< ", expectedExtras result text should == "
<< testCase.expectedExtras.result << ")";
}
};
class WindowsPinningAPIFixture
: public FOGFixtureWithParam<PinningAPITestCase> {};
TEST_P(WindowsPinningAPIFixture,
WindowsPinningTestTelemetryEventCreationCheckOnlyPrivateBrowsingOn) {
const auto testCase = GetParam();
const bool checkOnly = true;
const bool privateBrowsing = true;
TestPinning(checkOnly, PinningShortcutOperation::Succeed, testCase.result,
PinningFallbackOperation::Succeed, privateBrowsing);
// confirm we don't generate events when checking only
EXPECT_TRUE(telemetry_event::IsValidButEmpty(pinned_to_taskbar));
}
TEST_P(WindowsPinningAPIFixture,
WindowsPinningTestTelemetryEventCreationCheckOnlyPrivateBrowsingOff) {
const auto testCase = GetParam();
const bool checkOnly = true;
const bool privateBrowsing = false;
TestPinning(checkOnly, PinningShortcutOperation::Succeed, testCase.result,
PinningFallbackOperation::Succeed, privateBrowsing);
// confirm we don't generate events when checking only
EXPECT_TRUE(telemetry_event::IsValidButEmpty(pinned_to_taskbar));
}
static bool isFallbackSuccess(Win11PinToTaskBarResultStatus result) {
// fallback fails when the api succeeds
return (result != Win11PinToTaskBarResultStatus::Success) &&
(result != Win11PinToTaskBarResultStatus::AlreadyPinned);
}
TEST_P(WindowsPinningAPIFixture,
WindowsPinningTestTelemetryEventCreationPrivateBrowsingOn) {
auto testCase = GetParam();
const bool checkOnly = false;
const bool privateBrowsing = true;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(checkOnly, PinningShortcutOperation::Succeed, testCase.result,
PinningFallbackOperation::Succeed, privateBrowsing);
const bool fallbackSucceeded = isFallbackSuccess(testCase.result);
auto extras = telemetry::pinning::CreateEventExtra(
{S_OK, testCase.result, 1}, privateBrowsing, fallbackSucceeded);
EXPECT_TRUE(IsEqual(testCase.expectedExtras, extras));
size_t one = 1;
EXPECT_TRUE(telemetry_event::CountsMatch(pinned_to_taskbar, one));
auto metricsEvents = pinned_to_taskbar.TestGetValue().unwrap().ref();
auto control = testCase.expectedExtras;
EXPECT_TRUE(IsEqual(control, metricsEvents[0]));
}
TEST_P(WindowsPinningAPIFixture,
WindowsPinningTestTelemetryEventCreationPrivateBrowsingOff) {
auto testCase = GetParam();
const bool checkOnly = false;
const bool privateBrowsing = false;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(checkOnly, PinningShortcutOperation::Succeed, testCase.result,
PinningFallbackOperation::Succeed, privateBrowsing);
// fallback fails when the api succeeds
const bool fallbackSucceeded = isFallbackSuccess(testCase.result);
auto extras = telemetry::pinning::CreateEventExtra(
{S_OK, testCase.result, 1}, privateBrowsing, fallbackSucceeded);
EXPECT_TRUE(IsEqual(testCase.expectedExtras, extras));
size_t one = 1;
EXPECT_TRUE(telemetry_event::CountsMatch(pinned_to_taskbar, one));
auto metricsEvents = pinned_to_taskbar.TestGetValue().unwrap().ref();
auto control = testCase.expectedExtras;
EXPECT_TRUE(IsEqual(control, metricsEvents[0]));
}
static const PinningAPITestCase apiValidationTestCases[] = {
{.result = Win11PinToTaskBarResultStatus::NotSupported,
.expectedExtras = {.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_SUCCESS),
.notSupported = Some(true),
.numberOfAttempts = Some(1),
.result =
Some(telemetry::pinning::TELEMETRY_NOT_SUPPORTED)}},
{.result = Win11PinToTaskBarResultStatus::Success,
.expectedExtras = {.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_ERROR),
.numberOfAttempts = Some(1),
.result = Some(telemetry::pinning::TELEMETRY_SUCCESS),
.success = Some(true)}},
{.result = Win11PinToTaskBarResultStatus::AlreadyPinned,
.expectedExtras = {.alreadyPinned = Some(true),
.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_ERROR),
.numberOfAttempts = Some(1),
.result = Some(
telemetry::pinning::TELEMETRY_ALREADY_PINNED)}},
{.result = Win11PinToTaskBarResultStatus::NotCurrentlyAllowed,
.expectedExtras =
{.fallbackPinningSuccess = Some(telemetry::pinning::TELEMETRY_SUCCESS),
.notCurrentlyAllowed = Some(true),
.numberOfAttempts = Some(1),
.result = Some(telemetry::pinning::TELEMETRY_NOT_CURRENTLY_ALLOWED)}},
{.result = Win11PinToTaskBarResultStatus::Failed,
.expectedExtras = {.error = Some(true),
.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_SUCCESS),
.numberOfAttempts = Some(1),
.result = Some(telemetry::pinning::TELEMETRY_ERROR)}},
{.result = Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures,
.expectedExtras =
{.errorLimitedAccessFeatures = Some(true),
.fallbackPinningSuccess = Some(telemetry::pinning::TELEMETRY_SUCCESS),
.numberOfAttempts = Some(1),
.result = Some(
telemetry::pinning::TELEMETRY_ERROR_LIMITED_ACCESS_FEATURES)}},
{.result = Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked,
.expectedExtras =
{.fallbackPinningSuccess = Some(telemetry::pinning::TELEMETRY_SUCCESS),
.limitedAccessFeaturesLocked = Some(true),
.numberOfAttempts = Some(1),
.result = Some(
telemetry::pinning::TELEMETRY_LIMITED_ACCESS_FEATURES_LOCKED)}},
};
INSTANTIATE_TEST_SUITE_P(WindowsPinningAPITelemetryTests,
WindowsPinningAPIFixture,
::testing::ValuesIn(apiValidationTestCases));
class WindowsPinningAPIFallbackFixture
: public FOGFixtureWithParam<PinningAPITestCase> {};
TEST_P(WindowsPinningAPIFallbackFixture,
WindowsPinningTestFallbackFailsEventPrivateBrowsingOn) {
auto testCase = GetParam();
const bool checkOnly = false;
const bool privateBrowsing = true;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(checkOnly, PinningShortcutOperation::Succeed, testCase.result,
PinningFallbackOperation::Fail, privateBrowsing);
const bool fallbackSucceeded = false;
auto extras = telemetry::pinning::CreateEventExtra(
{S_OK, testCase.result, 1}, privateBrowsing, fallbackSucceeded);
EXPECT_TRUE(IsEqual(testCase.expectedExtras, extras));
auto metricsEvents = pinned_to_taskbar.TestGetValue().unwrap().ref();
auto control = testCase.expectedExtras;
EXPECT_TRUE(IsEqual(control, metricsEvents[0]));
}
TEST_P(WindowsPinningAPIFallbackFixture,
WindowsPinningTestFallbackFailsEventPrivateBrowsingOff) {
auto testCase = GetParam();
const bool checkOnly = false;
const bool privateBrowsing = false;
testCase.expectedExtras.privateBrowsing = Some(privateBrowsing);
TestPinning(checkOnly, PinningShortcutOperation::Succeed, testCase.result,
PinningFallbackOperation::Fail, privateBrowsing);
const bool fallbackSucceeded = false;
auto extras = telemetry::pinning::CreateEventExtra(
{S_OK, testCase.result, 1}, privateBrowsing, fallbackSucceeded);
EXPECT_TRUE(IsEqual(testCase.expectedExtras, extras));
auto metricsEvents = pinned_to_taskbar.TestGetValue().unwrap().ref();
auto control = testCase.expectedExtras;
EXPECT_TRUE(IsEqual(control, metricsEvents[0]));
}
static const PinningAPITestCase fallbackFailedTestCases[] = {
{.result = Win11PinToTaskBarResultStatus::NotSupported,
.expectedExtras = {.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_ERROR),
.notSupported = Some(true),
.numberOfAttempts = Some(1),
.result =
Some(telemetry::pinning::TELEMETRY_NOT_SUPPORTED)}},
{.result = Win11PinToTaskBarResultStatus::Success,
.expectedExtras = {.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_ERROR),
.numberOfAttempts = Some(1),
.result = Some(telemetry::pinning::TELEMETRY_SUCCESS),
.success = Some(true)}},
{.result = Win11PinToTaskBarResultStatus::AlreadyPinned,
.expectedExtras = {.alreadyPinned = Some(true),
.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_ERROR),
.numberOfAttempts = Some(1),
.result = Some(
telemetry::pinning::TELEMETRY_ALREADY_PINNED)}},
{.result = Win11PinToTaskBarResultStatus::NotCurrentlyAllowed,
.expectedExtras =
{.fallbackPinningSuccess = Some(telemetry::pinning::TELEMETRY_ERROR),
.notCurrentlyAllowed = Some(true),
.numberOfAttempts = Some(1),
.result = Some(telemetry::pinning::TELEMETRY_NOT_CURRENTLY_ALLOWED)}},
{.result = Win11PinToTaskBarResultStatus::Failed,
.expectedExtras = {.error = Some(true),
.fallbackPinningSuccess =
Some(telemetry::pinning::TELEMETRY_ERROR),
.numberOfAttempts = Some(1),
.result = Some(telemetry::pinning::TELEMETRY_ERROR)}},
{.result = Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures,
.expectedExtras =
{.errorLimitedAccessFeatures = Some(true),
.fallbackPinningSuccess = Some(telemetry::pinning::TELEMETRY_ERROR),
.numberOfAttempts = Some(1),
.result = Some(
telemetry::pinning::TELEMETRY_ERROR_LIMITED_ACCESS_FEATURES)}},
{.result = Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked,
.expectedExtras =
{.fallbackPinningSuccess = Some(telemetry::pinning::TELEMETRY_ERROR),
.limitedAccessFeaturesLocked = Some(true),
.numberOfAttempts = Some(1),
.result = Some(
telemetry::pinning::TELEMETRY_LIMITED_ACCESS_FEATURES_LOCKED)}},
};
INSTANTIATE_TEST_SUITE_P(WindowsPinningFallbackTelemetryTests,
WindowsPinningAPIFallbackFixture,
::testing::ValuesIn(fallbackFailedTestCases));

View File

@@ -1,14 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
LOCAL_INCLUDES += ["/browser/components/shell", "/toolkit/components/glean/tests"]
UNIFIED_SOURCES += [
"TaskbarPinningMetricsTests.cpp",
]
FINAL_LIBRARY = "xul-gtest"

View File

@@ -10,8 +10,6 @@ LOCAL_INCLUDES += ["/xpcom/build"]
BROWSER_CHROME_MANIFESTS += ["test/browser.toml"]
XPCSHELL_TESTS_MANIFESTS += ["test/unit/xpcshell.toml"]
TEST_DIRS += ["gtest"]
JAR_MANIFESTS += ["jar.mn"]
XPIDL_SOURCES += [

View File

@@ -5,11 +5,8 @@
#define UNICODE
#include "nsWindowsShellServiceInternal.h"
#include "nsWindowsShellService.h"
#include "mozilla/glean/GleanMetrics.h"
#include "BinaryPath.h"
#include "imgIContainer.h"
#include "imgIRequest.h"
@@ -1640,28 +1637,26 @@ static nsresult PinCurrentAppToTaskbarWin10(bool aCheckOnly,
return ManageShortcutTaskbarPins(aCheckOnly, pinType, aShortcutPath);
}
void PinCurrentAppToTaskbarHelper::CheckNotMainThread() {
static nsresult PinCurrentAppToTaskbarImpl(
bool aCheckOnly, bool aPrivateBrowsing, const nsAString& aAppUserModelId,
const nsAString& aShortcutName, const nsAString& aShortcutSubstring,
nsIFile* aShortcutsLogDir, nsIFile* aGreDir, nsIFile* aProgramsDir) {
MOZ_DIAGNOSTIC_ASSERT(
!NS_IsMainThread(),
"PinCurrentAppToTaskbarImpl should be called off main thread only");
}
Result<bool, nsresult> PinCurrentAppToTaskbarHelper::CreateShortcutForTaskbar(
bool aCheckOnly, bool aPrivateBrowsing, const nsAString& aAppUserModelId,
const nsAString& aShortcutName, const nsAString& aShortcutSubstring,
nsIFile* aShortcutsLogDir, nsIFile* aGreDir, nsIFile* aProgramsDir,
nsAutoString& aShortcutPath) {
nsAutoString shortcutPath;
nsresult rv = FindMatchingShortcut(aAppUserModelId, aShortcutSubstring,
aPrivateBrowsing, aShortcutPath);
aPrivateBrowsing, shortcutPath);
if (NS_FAILED(rv)) {
aShortcutPath.Truncate();
shortcutPath.Truncate();
}
if (aShortcutPath.IsEmpty()) {
if (shortcutPath.IsEmpty()) {
if (aCheckOnly) {
// Later checks rely on a shortcut already existing.
// We don't want to create a shortcut in check only mode
// so the best we can do is assume those parts will work.
return false;
return NS_OK;
}
nsAutoString linkName(aShortcutName);
@@ -1671,23 +1666,23 @@ Result<bool, nsresult> PinCurrentAppToTaskbarHelper::CreateShortcutForTaskbar(
nsAutoString pbExeStr(PRIVATE_BROWSING_BINARY);
nsresult rv = exeFile->Append(pbExeStr);
if (!NS_SUCCEEDED(rv)) {
return Err(NS_ERROR_FAILURE);
return NS_ERROR_FAILURE;
}
} else {
wchar_t exePath[MAXPATHLEN] = {};
if (NS_WARN_IF(NS_FAILED(BinaryPath::GetLong(exePath)))) {
return Err(NS_ERROR_FAILURE);
return NS_ERROR_FAILURE;
}
nsAutoString exeStr(exePath);
nsresult rv = NS_NewLocalFile(exeStr, true, getter_AddRefs(exeFile));
if (!NS_SUCCEEDED(rv)) {
return Err(NS_ERROR_FILE_NOT_FOUND);
return NS_ERROR_FILE_NOT_FOUND;
}
}
nsCOMPtr<nsIFile> shortcutFile(aProgramsDir);
shortcutFile->Append(aShortcutName);
aShortcutPath.Assign(shortcutFile->NativePath());
shortcutPath.Assign(shortcutFile->NativePath());
nsTArray<nsString> arguments;
rv = CreateShortcutImpl(exeFile, arguments, aShortcutName, exeFile,
@@ -1697,62 +1692,12 @@ Result<bool, nsresult> PinCurrentAppToTaskbarHelper::CreateShortcutForTaskbar(
linkName, shortcutFile->NativePath(),
aShortcutsLogDir);
if (!NS_SUCCEEDED(rv)) {
return Err(NS_ERROR_FILE_NOT_FOUND);
return NS_ERROR_FILE_NOT_FOUND;
}
}
return true;
}
Win11PinToTaskBarResult PinCurrentAppToTaskbarHelper::PinCurrentAppViaAPI(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) {
return PinCurrentAppToTaskbarWin11(aCheckOnly, aAppUserModelId,
aShortcutPath);
}
nsresult PinCurrentAppToTaskbarHelper::PinCurrentAppFallback(
bool aCheckOnly, const nsAString& aAppUserModelId,
const nsAString& aShortcutPath) {
return PinCurrentAppToTaskbarWin10(aCheckOnly, aAppUserModelId,
aShortcutPath);
}
nsresult PinCurrentAppToTaskbarImpl(
bool aCheckOnly, bool aPrivateBrowsing, const nsAString& aAppUserModelId,
const nsAString& aShortcutName, const nsAString& aShortcutSubstring,
nsIFile* aShortcutsLogDir, nsIFile* aGreDir, nsIFile* aProgramsDir,
UniquePtr<PinCurrentAppToTaskbarHelper> helper) {
if (!helper) {
helper.reset(new PinCurrentAppToTaskbarHelper);
}
helper->CheckNotMainThread();
nsAutoString shortcutPath;
auto shortcutResult = helper->CreateShortcutForTaskbar(
aCheckOnly, aPrivateBrowsing, aAppUserModelId, aShortcutName,
aShortcutSubstring, aShortcutsLogDir, aGreDir, aProgramsDir,
shortcutPath);
if (shortcutResult.isErr()) {
nsresult err = shortcutResult.unwrapErr();
telemetry::shortcut::Record(aCheckOnly, err, aPrivateBrowsing);
return err;
} else {
if (!shortcutResult.unwrap()) {
return NS_OK;
}
}
telemetry::shortcut::Record(aCheckOnly, NS_OK, aPrivateBrowsing);
auto pinWithWin11TaskbarAPIResults =
helper->PinCurrentAppViaAPI(aCheckOnly, aAppUserModelId, shortcutPath);
PinCurrentAppToTaskbarWin11(aCheckOnly, aAppUserModelId, shortcutPath);
switch (pinWithWin11TaskbarAPIResults.result) {
case Win11PinToTaskBarResultStatus::NotSupported:
// Fall through to the win 10 mechanism
@@ -1760,21 +1705,9 @@ nsresult PinCurrentAppToTaskbarImpl(
case Win11PinToTaskBarResultStatus::Success:
case Win11PinToTaskBarResultStatus::AlreadyPinned:
telemetry::pinning::Record(aCheckOnly, pinWithWin11TaskbarAPIResults,
aPrivateBrowsing, false);
return NS_OK;
case Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures:
case Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked:
case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed:
// return NS_ERROR_FAILURE;
// Fall through to the old mechanism for now
// In future, we should be sending telemetry for when
// an error occurs or for when pinning is not allowed
// with the Win 11 APIs.
break;
case Win11PinToTaskBarResultStatus::Failed:
// return NS_ERROR_FAILURE;
@@ -1785,13 +1718,7 @@ nsresult PinCurrentAppToTaskbarImpl(
break;
}
auto result =
helper->PinCurrentAppFallback(aCheckOnly, aAppUserModelId, shortcutPath);
telemetry::pinning::Record(aCheckOnly, pinWithWin11TaskbarAPIResults,
aPrivateBrowsing, NS_SUCCEEDED(result));
return result;
return PinCurrentAppToTaskbarWin10(aCheckOnly, aAppUserModelId, shortcutPath);
}
static nsresult PinCurrentAppToTaskbarAsyncImpl(bool aCheckOnly,

View File

@@ -1,189 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
#ifndef nswindowsshellserviceinternal_h____
#define nswindowsshellserviceinternal_h____
#include "nsString.h"
#include <mozilla/DefineEnum.h>
#include "mozilla/Result.h"
#include "mozilla/ResultVariant.h"
#include "mozilla/UniquePtr.h"
#include <windows.h>
#include "mozilla/glean/GleanMetrics.h"
#include "Windows11TaskbarPinning.h"
/**
* Namespace to wrap recording of telemetry and separate it from everything
* else. Should be easy to move into a class if it needs to be stubbed later for
* testing purposes.
*/
namespace telemetry {
namespace shortcut {
static const auto TELEMETRY_SUCCESS = "Success"_ns;
static const auto TELEMETRY_FILE_NOT_FOUND = "FileNotFound"_ns;
static const auto TELEMETRY_ERROR = "Error"_ns;
inline mozilla::glean::pinning_windows::ShortcutCreatedExtra CreateEventExtra(
nsresult result, bool aPrivateBrowsing) {
using namespace mozilla::glean::pinning_windows;
using namespace mozilla;
switch (result) {
case NS_OK:
return ShortcutCreatedExtra{.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_SUCCESS),
.success = Some(true)};
case NS_ERROR_FILE_NOT_FOUND:
return ShortcutCreatedExtra{.fileNotFound = Some(true),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_FILE_NOT_FOUND)};
default:
return ShortcutCreatedExtra{.error = Some(true),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_ERROR)};
}
}
inline void Record(bool aCheckOnly, nsresult result, bool aPrivateBrowsing) {
using namespace mozilla::glean::pinning_windows;
using namespace mozilla;
if (!aCheckOnly) {
shortcut_created.Record(Some(CreateEventExtra(result, aPrivateBrowsing)));
}
}
} // namespace shortcut
namespace pinning {
static const auto TELEMETRY_NOT_SUPPORTED = "NotSupported"_ns;
static const auto TELEMETRY_SUCCESS = "Success"_ns;
static const auto TELEMETRY_ALREADY_PINNED = "AlreadyPinned"_ns;
static const auto TELEMETRY_NOT_CURRENTLY_ALLOWED = "NotCurrentlyAllowed"_ns;
static const auto TELEMETRY_ERROR = "Error"_ns;
static const auto TELEMETRY_ERROR_LIMITED_ACCESS_FEATURES =
"ErrorLimitedAccessFeatures"_ns;
static const auto TELEMETRY_LIMITED_ACCESS_FEATURES_LOCKED =
"LimitedAccessFeaturesLocked"_ns;
inline mozilla::glean::pinning_windows::PinnedToTaskbarExtra CreateEventExtra(
Win11PinToTaskBarResult result, bool aPrivateBrowsing,
bool fallbackSucceeded) {
using namespace mozilla::glean::pinning_windows;
using namespace mozilla;
const auto fallbackResultString =
fallbackSucceeded ? TELEMETRY_SUCCESS : TELEMETRY_ERROR;
auto resultStatus = result.result;
switch (resultStatus) {
case Win11PinToTaskBarResultStatus::NotSupported:
return {.fallbackPinningSuccess = Some(fallbackResultString),
.notSupported = Some(true),
.numberOfAttempts = Some(result.numAttempts),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_NOT_SUPPORTED)};
case Win11PinToTaskBarResultStatus::Success:
return {.fallbackPinningSuccess = Some(fallbackResultString),
.numberOfAttempts = Some(result.numAttempts),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_SUCCESS),
.success = Some(true)};
case Win11PinToTaskBarResultStatus::AlreadyPinned:
return {.alreadyPinned = Some(true),
.fallbackPinningSuccess = Some(fallbackResultString),
.numberOfAttempts = Some(result.numAttempts),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_ALREADY_PINNED)};
case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed:
return {.fallbackPinningSuccess = Some(fallbackResultString),
.notCurrentlyAllowed = Some(true),
.numberOfAttempts = Some(result.numAttempts),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_NOT_CURRENTLY_ALLOWED)};
case Win11PinToTaskBarResultStatus::ErrorLimitedAccessFeatures:
return {.errorLimitedAccessFeatures = Some(true),
.fallbackPinningSuccess = Some(fallbackResultString),
.numberOfAttempts = Some(result.numAttempts),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_ERROR_LIMITED_ACCESS_FEATURES)};
case Win11PinToTaskBarResultStatus::LimitedAccessFeaturesLocked:
return {.fallbackPinningSuccess = Some(fallbackResultString),
.limitedAccessFeaturesLocked = Some(true),
.numberOfAttempts = Some(result.numAttempts),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_LIMITED_ACCESS_FEATURES_LOCKED)};
case Win11PinToTaskBarResultStatus::Failed:
default:
return {.error = Some(true),
.fallbackPinningSuccess = Some(fallbackResultString),
.numberOfAttempts = Some(result.numAttempts),
.privateBrowsing = Some(aPrivateBrowsing),
.result = Some(TELEMETRY_ERROR)};
}
}
inline void Record(bool aCheckOnly, Win11PinToTaskBarResult result,
bool aPrivateBrowsing, bool fallbackSucceeded) {
using namespace mozilla::glean::pinning_windows;
using namespace mozilla;
if (!aCheckOnly) {
pinned_to_taskbar.Record(
Some(CreateEventExtra(result, aPrivateBrowsing, fallbackSucceeded)));
}
}
} // namespace pinning
} // namespace telemetry
/**
* Helper class to wrap calling the logic for taskbar pinning. Specifically done
* this way so that it can be stubbed out with a mock implementation for testing
* metrics are collected properly. The base class includes the default
* implementation that should be used outside of testing and is a light wrapper
* around static functions.
*/
class PinCurrentAppToTaskbarHelper {
public:
virtual ~PinCurrentAppToTaskbarHelper() {}
virtual void CheckNotMainThread();
virtual mozilla::Result<bool, nsresult> CreateShortcutForTaskbar(
bool aCheckOnly, bool aPrivateBrowsing, const nsAString& aAppUserModelId,
const nsAString& aShortcutName, const nsAString& aShortcutSubstring,
nsIFile* aShortcutsLogDir, nsIFile* aGreDir, nsIFile* aProgramsDir,
nsAutoString& aShortcutPath);
virtual Win11PinToTaskBarResult PinCurrentAppViaAPI(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath);
virtual nsresult PinCurrentAppFallback(bool aCheckOnly,
const nsAString& aAppUserModelId,
const nsAString& aShortcutPath);
};
class nsIFile;
nsresult PinCurrentAppToTaskbarImpl(
bool aCheckOnly, bool aPrivateBrowsing, const nsAString& aAppUserModelId,
const nsAString& aShortcutName, const nsAString& aShortcutSubstring,
nsIFile* aShortcutsLogDir, nsIFile* aGreDir, nsIFile* aProgramsDir,
mozilla::UniquePtr<PinCurrentAppToTaskbarHelper> helper =
mozilla::UniquePtr<PinCurrentAppToTaskbarHelper>());
#endif // nswindowsshellserviceinternal_h____

View File

@@ -14,24 +14,10 @@ using namespace mozilla::glean::impl;
class FOGFixture : public ::testing::Test {
protected:
FOGFixture() = default;
virtual void SetUp() { TestResetFOG(); }
public:
static void TestResetFOG() {
virtual void SetUp() {
nsCString empty;
ASSERT_EQ(NS_OK, fog_test_reset(&empty, &empty));
}
};
template <typename ParamType>
class FOGFixtureWithParam : public ::testing::TestWithParam<ParamType> {
protected:
FOGFixtureWithParam() = default;
virtual void SetUp() { TestResetFOG(); }
// Can be called by derived fixtures
void TestResetFOG() { FOGFixture::TestResetFOG(); }
};
#endif // FOGFixture_h_