blob: 75ff7dd07950cb32f9521ec2c476733f2987b893 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/forced_extensions/force_installed_metrics.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "base/timer/mock_timer.h"
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/external_provider_impl.h"
#include "chrome/browser/extensions/forced_extensions/force_installed_test_base.h"
#include "chrome/browser/extensions/forced_extensions/force_installed_tracker.h"
#include "chrome/browser/extensions/forced_extensions/install_stage_tracker.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/disable_reason.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/install/crx_install_error.h"
#include "extensions/browser/install/sandboxed_unpacker_failure_reason.h"
#include "extensions/browser/pref_names.h"
#include "extensions/browser/updater/safe_manifest_parser.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest.h"
#include "extensions/common/value_builder.h"
#include "net/base/net_errors.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "components/arc/arc_prefs.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user_names.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace {
// Intentionally invalid extension id.
constexpr char kExtensionId3[] = "cdefghijklmnopqrstuvwxyzabcdefgh";
const int kFetchTries = 5;
// HTTP_UNAUTHORIZED
const int kResponseCode = 401;
constexpr char kLoadTimeStats[] = "Extensions.ForceInstalledLoadTime";
constexpr char kReadyTimeStats[] = "Extensions.ForceInstalledReadyTime";
constexpr char kTimedOutStats[] = "Extensions.ForceInstalledTimedOutCount";
constexpr char kTimedOutNotInstalledStats[] =
"Extensions.ForceInstalledTimedOutAndNotInstalledCount";
constexpr char kInstallationFailureCacheStatus[] =
"Extensions.ForceInstalledFailureCacheStatus";
constexpr char kFailureReasonsCWS[] =
"Extensions.WebStore_ForceInstalledFailureReason3";
constexpr char kFailureReasonsSH[] =
"Extensions.OffStore_ForceInstalledFailureReason3";
constexpr char kInstallationStages[] = "Extensions.ForceInstalledStage2";
constexpr char kInstallCreationStages[] =
"Extensions.ForceInstalledCreationStage";
constexpr char kInstallationDownloadingStages[] =
"Extensions.ForceInstalledDownloadingStage";
constexpr char kFailureCrxInstallErrorStats[] =
"Extensions.ForceInstalledFailureCrxInstallError";
constexpr char kTotalCountStats[] =
"Extensions.ForceInstalledTotalCandidateCount";
constexpr char kNetworkErrorCodeStats[] =
"Extensions.ForceInstalledNetworkErrorCode";
constexpr char kHttpErrorCodeStats[] =
"Extensions.ForceInstalledHttpErrorCode2";
constexpr char kFetchRetriesStats[] = "Extensions.ForceInstalledFetchTries";
constexpr char kNetworkErrorCodeManifestFetchFailedStats[] =
"Extensions.ForceInstalledManifestFetchFailedNetworkErrorCode";
constexpr char kHttpErrorCodeManifestFetchFailedStats[] =
"Extensions.ForceInstalledManifestFetchFailedHttpErrorCode2";
constexpr char kFetchRetriesManifestFetchFailedStats[] =
"Extensions.ForceInstalledManifestFetchFailedFetchTries";
constexpr char kSandboxUnpackFailureReason[] =
"Extensions.ForceInstalledFailureSandboxUnpackFailureReason";
#if BUILDFLAG(IS_CHROMEOS_ASH)
constexpr char kFailureSessionStats[] =
"Extensions.ForceInstalledFailureSessionType";
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
constexpr char kPossibleNonMisconfigurationFailures[] =
"Extensions.ForceInstalledSessionsWithNonMisconfigurationFailureOccured";
constexpr char kDisableReason[] =
"Extensions.ForceInstalledNotLoadedDisableReason";
constexpr char kBlocklisted[] = "Extensions.ForceInstalledAndBlackListed";
constexpr char kExtensionManifestInvalid[] =
"Extensions.ForceInstalledFailureManifestInvalidErrorDetail2";
constexpr char kManifestNoUpdatesInfo[] =
"Extensions.ForceInstalledFailureNoUpdatesInfo";
constexpr char kExtensionManifestInvalidAppStatusError[] =
"Extensions.ForceInstalledFailureManifestInvalidAppStatusError";
constexpr char kManifestDownloadTimeStats[] =
"Extensions.ForceInstalledTime.DownloadingStartTo.ManifestDownloadComplete";
constexpr char kCRXDownloadTimeStats[] =
"Extensions.ForceInstalledTime.ManifestDownloadCompleteTo."
"CRXDownloadComplete";
constexpr char kVerificationTimeStats[] =
"Extensions.ForceInstalledTime.VerificationStartTo.CopyingStart";
constexpr char kCopyingTimeStats[] =
"Extensions.ForceInstalledTime.CopyingStartTo.UnpackingStart";
constexpr char kUnpackingTimeStats[] =
"Extensions.ForceInstalledTime.UnpackingStartTo.CheckingExpectationsStart";
constexpr char kCheckingExpectationsTimeStats[] =
"Extensions.ForceInstalledTime.CheckingExpectationsStartTo.FinalizingStart";
constexpr char kFinalizingTimeStats[] =
"Extensions.ForceInstalledTime.FinalizingStartTo.CRXInstallComplete";
constexpr char kCrxHeaderInvalidFailureIsCWS[] =
"Extensions.ForceInstalledFailureWithCrxHeaderInvalidIsCWS";
constexpr char kCrxHeaderInvalidFailureFromCache[] =
"Extensions.ForceInstalledFailureWithCrxHeaderInvalidIsFromCache";
} // namespace
namespace extensions {
using ExtensionStatus = ForceInstalledTracker::ExtensionStatus;
using testing::_;
using testing::Return;
class ForceInstalledMetricsTest : public ForceInstalledTestBase {
public:
ForceInstalledMetricsTest() = default;
ForceInstalledMetricsTest(const ForceInstalledMetricsTest&) = delete;
ForceInstalledMetricsTest& operator=(const ForceInstalledMetricsTest&) =
delete;
void SetUp() override {
ForceInstalledTestBase::SetUp();
auto fake_timer = std::make_unique<base::MockOneShotTimer>();
fake_timer_ = fake_timer.get();
metrics_ = std::make_unique<ForceInstalledMetrics>(
registry(), profile(), force_installed_tracker(),
std::move(fake_timer));
}
void SetupExtensionManagementPref() {
std::unique_ptr<base::DictionaryValue> extension_entry =
DictionaryBuilder()
.Set("installation_mode", "allowed")
.Set(ExternalProviderImpl::kExternalUpdateUrl, kExtensionUpdateUrl)
.Build();
prefs()->SetManagedPref(pref_names::kExtensionManagement,
DictionaryBuilder()
.Set(kExtensionId1, std::move(extension_entry))
.Build());
}
// Report downloading manifest stage for both the extensions.
void ReportDownloadingManifestStage() {
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1,
ExtensionDownloaderDelegate::Stage::DOWNLOADING_MANIFEST);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId2,
ExtensionDownloaderDelegate::Stage::DOWNLOADING_MANIFEST);
}
void ReportInstallationStarted(base::Optional<base::TimeDelta> install_time) {
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1, ExtensionDownloaderDelegate::Stage::MANIFEST_LOADED);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1, ExtensionDownloaderDelegate::Stage::DOWNLOADING_CRX);
if (install_time)
task_environment_.FastForwardBy(install_time.value());
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1, ExtensionDownloaderDelegate::Stage::FINISHED);
install_stage_tracker()->ReportInstallationStage(
kExtensionId1, InstallStageTracker::Stage::INSTALLING);
}
protected:
base::HistogramTester histogram_tester_;
base::MockOneShotTimer* fake_timer_;
std::unique_ptr<ForceInstalledMetrics> metrics_;
};
TEST_F(ForceInstalledMetricsTest, EmptyForcelist) {
SetupEmptyForceList();
EXPECT_FALSE(fake_timer_->IsRunning());
// Don't report metrics when the Forcelist is empty.
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectTotalCount(kReadyTimeStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutNotInstalledStats, 0);
histogram_tester_.ExpectTotalCount(kFailureReasonsCWS, 0);
histogram_tester_.ExpectTotalCount(kFailureReasonsSH, 0);
histogram_tester_.ExpectTotalCount(kInstallationStages, 0);
histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0);
histogram_tester_.ExpectTotalCount(kTotalCountStats, 0);
}
TEST_F(ForceInstalledMetricsTest, ExtensionsInstalled) {
SetupForceList(true /*is_from_store */);
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::LOADED);
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 1);
histogram_tester_.ExpectTotalCount(kReadyTimeStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutNotInstalledStats, 0);
histogram_tester_.ExpectTotalCount(kFailureReasonsCWS, 0);
histogram_tester_.ExpectTotalCount(kFailureReasonsSH, 0);
histogram_tester_.ExpectTotalCount(kInstallationStages, 0);
histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0);
histogram_tester_.ExpectUniqueSample(
kTotalCountStats,
prefs()->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1);
}
// Verifies that failure is reported for the extensions which are listed in
// forced list, and their installation mode are overridden by ExtensionSettings
// policy to something else.
TEST_F(ForceInstalledMetricsTest, ExtensionSettingsOverrideForcedList) {
SetupForceList(true /*is_from_store */);
SetupExtensionManagementPref();
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::LOADED);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(
kFailureReasonsCWS,
InstallStageTracker::FailureReason::OVERRIDDEN_BY_SETTINGS, 1);
}
TEST_F(ForceInstalledMetricsTest, ExtensionsInstallationTimedOut) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::PENDING);
registry()->AddEnabled(ext.get());
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
// Metrics are reported due to timeout.
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectUniqueSample(kTimedOutStats, 2, 1);
histogram_tester_.ExpectUniqueSample(kTimedOutNotInstalledStats, 1, 1);
histogram_tester_.ExpectTotalCount(kFailureReasonsCWS, 1);
histogram_tester_.ExpectUniqueSample(
kFailureReasonsCWS, InstallStageTracker::FailureReason::IN_PROGRESS, 1);
histogram_tester_.ExpectTotalCount(kInstallationStages, 1);
histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0);
histogram_tester_.ExpectUniqueSample(
kTotalCountStats,
prefs()->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1);
}
// Reporting the time for downloading the manifest of an extension and verifying
// that it is correctly recorded in the histogram.
TEST_F(ForceInstalledMetricsTest, ExtensionsManifestDownloadTime) {
SetupForceList(true /*is_from_store */);
ReportDownloadingManifestStage();
const base::TimeDelta manifest_download_time =
base::TimeDelta::FromMilliseconds(200);
task_environment_.FastForwardBy(manifest_download_time);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1, ExtensionDownloaderDelegate::Stage::MANIFEST_LOADED);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::MANIFEST_INVALID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kManifestDownloadTimeStats, 1);
histogram_tester_.ExpectTimeBucketCount(kManifestDownloadTimeStats,
manifest_download_time, 1);
}
// Reporting the time for downloading the CRX file of an extension and verifying
// that it is correctly recorded in the histogram.
TEST_F(ForceInstalledMetricsTest, ExtensionsCrxDownloadTime) {
SetupForceList(true /*is_from_store */);
ReportDownloadingManifestStage();
const base::TimeDelta install_time = base::TimeDelta::FromMilliseconds(200);
ReportInstallationStarted(install_time);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::MANIFEST_INVALID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kCRXDownloadTimeStats, 1);
histogram_tester_.ExpectTimeBucketCount(kCRXDownloadTimeStats, install_time,
1);
}
TEST_F(ForceInstalledMetricsTest,
ExtensionsCrxDownloadTimeWhenFetchedFromCache) {
SetupForceList(true /*is_from_store */);
ReportDownloadingManifestStage();
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1, ExtensionDownloaderDelegate::Stage::MANIFEST_LOADED);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1, ExtensionDownloaderDelegate::Stage::FINISHED);
install_stage_tracker()->ReportInstallationStage(
kExtensionId1, InstallStageTracker::Stage::INSTALLING);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::MANIFEST_INVALID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
// Time should not be recorded when CRX is fetched from cache.
histogram_tester_.ExpectTotalCount(kCRXDownloadTimeStats, 0);
}
// Reporting the times for various stages in the extension installation process
// and verifying that the time consumed at each stage is correctly recorded in
// the histogram.
TEST_F(ForceInstalledMetricsTest, ExtensionsReportInstallationStageTimes) {
SetupForceList(true /*is_from_store */);
ReportDownloadingManifestStage();
ReportInstallationStarted(base::nullopt);
install_stage_tracker()->ReportCRXInstallationStage(
kExtensionId1, InstallationStage::kVerification);
const base::TimeDelta installation_stage_time =
base::TimeDelta::FromMilliseconds(200);
task_environment_.FastForwardBy(installation_stage_time);
install_stage_tracker()->ReportCRXInstallationStage(
kExtensionId1, InstallationStage::kCopying);
task_environment_.FastForwardBy(installation_stage_time);
install_stage_tracker()->ReportCRXInstallationStage(
kExtensionId1, InstallationStage::kUnpacking);
task_environment_.FastForwardBy(installation_stage_time);
install_stage_tracker()->ReportCRXInstallationStage(
kExtensionId1, InstallationStage::kCheckingExpectations);
task_environment_.FastForwardBy(installation_stage_time);
install_stage_tracker()->ReportCRXInstallationStage(
kExtensionId1, InstallationStage::kFinalizing);
task_environment_.FastForwardBy(installation_stage_time);
install_stage_tracker()->ReportCRXInstallationStage(
kExtensionId1, InstallationStage::kComplete);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::MANIFEST_INVALID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kVerificationTimeStats, 1);
histogram_tester_.ExpectTimeBucketCount(kVerificationTimeStats,
installation_stage_time, 1);
histogram_tester_.ExpectTotalCount(kCopyingTimeStats, 1);
histogram_tester_.ExpectTimeBucketCount(kCopyingTimeStats,
installation_stage_time, 1);
histogram_tester_.ExpectTotalCount(kUnpackingTimeStats, 1);
histogram_tester_.ExpectTimeBucketCount(kUnpackingTimeStats,
installation_stage_time, 1);
histogram_tester_.ExpectTotalCount(kCheckingExpectationsTimeStats, 1);
histogram_tester_.ExpectTimeBucketCount(kCheckingExpectationsTimeStats,
installation_stage_time, 1);
histogram_tester_.ExpectTotalCount(kFinalizingTimeStats, 1);
histogram_tester_.ExpectTimeBucketCount(kFinalizingTimeStats,
installation_stage_time, 1);
}
// Reporting disable reason for the force installed extensions which are
// installed but not loaded when extension is disable due to single reason.
TEST_F(ForceInstalledMetricsTest,
ExtensionsInstalledButNotLoadedUniqueDisableReason) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::PENDING);
registry()->AddDisabled(ext1.get());
ExtensionPrefs::Get(profile())->AddDisableReason(
kExtensionId1, disable_reason::DisableReason::DISABLE_NOT_VERIFIED);
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::PENDING);
registry()->AddEnabled(ext2.get());
force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
// ForceInstalledMetrics should still keep running as kExtensionId1 is
// installed but not loaded.
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectUniqueSample(
kDisableReason, disable_reason::DisableReason::DISABLE_NOT_VERIFIED, 1);
}
// Reporting disable reasons for the force installed extensions which are
// installed but not loaded when extension is disable due to multiple reasons.
TEST_F(ForceInstalledMetricsTest,
ExtensionsInstalledButNotLoadedMultipleDisableReason) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::PENDING);
registry()->AddDisabled(ext1.get());
ExtensionPrefs::Get(profile())->AddDisableReasons(
kExtensionId1,
disable_reason::DisableReason::DISABLE_NOT_VERIFIED |
disable_reason::DisableReason::DISABLE_UNSUPPORTED_REQUIREMENT);
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::PENDING);
registry()->AddEnabled(ext2.get());
force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
// ForceInstalledMetrics should still keep running as kExtensionId1 is
// installed but not loaded.
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
// Verifies that only one disable reason is reported;
histogram_tester_.ExpectUniqueSample(
kDisableReason,
disable_reason::DisableReason::DISABLE_UNSUPPORTED_REQUIREMENT, 1);
}
// Reporting DisableReason::DISABLE_NONE for the force installed extensions
// which are installed but not loaded when extension is enabled.
TEST_F(ForceInstalledMetricsTest,
ExtensionsInstalledButNotLoadedNoDisableReason) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::PENDING);
registry()->AddEnabled(ext1.get());
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::PENDING);
registry()->AddEnabled(ext2.get());
force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
// ForceInstalledMetrics should still keep running as kExtensionId1 is
// installed but not loaded.
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectUniqueSample(
kDisableReason, disable_reason::DisableReason::DISABLE_NONE, 1);
}
TEST_F(ForceInstalledMetricsTest, ExtensionForceInstalledAndBlocklisted) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::PENDING);
registry()->AddBlocklisted(ext1.get());
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::PENDING);
registry()->AddEnabled(ext2.get());
force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
// ForceInstalledMetrics should still keep running as kExtensionId1 is
// installed but not loaded.
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectUniqueSample(kBlocklisted, 1, 1);
}
TEST_F(ForceInstalledMetricsTest, ExtensionsInstallationCancelled) {
SetupForceList(true /*is_from_store */);
SetupEmptyForceList();
// ForceInstalledMetrics does not shut down the timer, because it's still
// waiting for the initial extensions to install.
EXPECT_TRUE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutNotInstalledStats, 0);
histogram_tester_.ExpectTotalCount(kFailureReasonsCWS, 0);
histogram_tester_.ExpectTotalCount(kInstallationStages, 0);
histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0);
histogram_tester_.ExpectTotalCount(kTotalCountStats, 0);
}
TEST_F(ForceInstalledMetricsTest, ForcedExtensionsAddedAfterManualExtensions) {
// Report failure for an extension which is not in forced list.
install_stage_tracker()->ReportFailure(
kExtensionId3, InstallStageTracker::FailureReason::INVALID_ID);
// ForceInstalledMetrics should keep running as the forced extensions are
// still not loaded.
EXPECT_TRUE(fake_timer_->IsRunning());
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::READY);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::INVALID_ID);
// ForceInstalledMetrics shuts down timer because kExtensionId1 was loaded and
// kExtensionId2 was failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(
kFailureReasonsCWS, InstallStageTracker::FailureReason::INVALID_ID, 1);
}
TEST_F(ForceInstalledMetricsTest,
ExtensionsInstallationTimedOutDifferentReasons) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportFailure(
kExtensionId1, InstallStageTracker::FailureReason::INVALID_ID);
install_stage_tracker()->ReportCrxInstallError(
kExtensionId2,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_OTHER,
CrxInstallErrorDetail::UNEXPECTED_ID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectUniqueSample(kTimedOutStats, 2, 1);
histogram_tester_.ExpectUniqueSample(kTimedOutNotInstalledStats, 2, 1);
histogram_tester_.ExpectTotalCount(kFailureReasonsCWS, 2);
histogram_tester_.ExpectBucketCount(
kFailureReasonsCWS, InstallStageTracker::FailureReason::INVALID_ID, 1);
histogram_tester_.ExpectBucketCount(
kFailureReasonsCWS,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_OTHER, 1);
histogram_tester_.ExpectTotalCount(kInstallationStages, 0);
histogram_tester_.ExpectUniqueSample(kFailureCrxInstallErrorStats,
CrxInstallErrorDetail::UNEXPECTED_ID, 1);
histogram_tester_.ExpectUniqueSample(
kTotalCountStats,
prefs()->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1);
}
// Reporting SandboxedUnpackerFailureReason when the force installed extension
// fails to install with error CRX_INSTALL_ERROR_SANDBOXED_UNPACKER_FAILURE.
TEST_F(ForceInstalledMetricsTest,
ExtensionsCrxInstallErrorSandboxUnpackFailure) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportSandboxedUnpackerFailureReason(
kExtensionId1,
CrxInstallError(SandboxedUnpackerFailureReason::CRX_FILE_NOT_READABLE,
base::string16()));
install_stage_tracker()->ReportSandboxedUnpackerFailureReason(
kExtensionId2,
CrxInstallError(SandboxedUnpackerFailureReason::UNZIP_FAILED,
base::string16()));
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kSandboxUnpackFailureReason, 2);
histogram_tester_.ExpectBucketCount(
kSandboxUnpackFailureReason,
SandboxedUnpackerFailureReason::CRX_FILE_NOT_READABLE, 1);
histogram_tester_.ExpectBucketCount(
kSandboxUnpackFailureReason, SandboxedUnpackerFailureReason::UNZIP_FAILED,
1);
}
// Reporting when the extension is downloaded from cache and it fails to install
// with error CRX_HEADER_INVALID.
TEST_F(ForceInstalledMetricsTest, ExtensionsCrxHeaderInvalidFromCache) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportDownloadingCacheStatus(
kExtensionId1, ExtensionDownloaderDelegate::CacheStatus::CACHE_HIT);
install_stage_tracker()->ReportSandboxedUnpackerFailureReason(
kExtensionId1,
CrxInstallError(SandboxedUnpackerFailureReason::CRX_HEADER_INVALID,
base::string16()));
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::PENDING);
registry()->AddEnabled(ext2.get());
force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kSandboxUnpackFailureReason, 1);
histogram_tester_.ExpectBucketCount(
kSandboxUnpackFailureReason,
SandboxedUnpackerFailureReason::CRX_HEADER_INVALID, 1);
histogram_tester_.ExpectBucketCount(kCrxHeaderInvalidFailureIsCWS, true, 1);
histogram_tester_.ExpectBucketCount(kCrxHeaderInvalidFailureFromCache, true,
1);
}
// Reporting when the extension is not downloaded from cache and it fails to
// install with error CRX_HEADER_INVALID.
TEST_F(ForceInstalledMetricsTest, ExtensionsCrxHeaderInvalidNotFromCache) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportDownloadingCacheStatus(
kExtensionId1, ExtensionDownloaderDelegate::CacheStatus::CACHE_MISS);
install_stage_tracker()->ReportSandboxedUnpackerFailureReason(
kExtensionId1,
CrxInstallError(SandboxedUnpackerFailureReason::CRX_HEADER_INVALID,
base::string16()));
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::PENDING);
registry()->AddEnabled(ext2.get());
force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kSandboxUnpackFailureReason, 1);
histogram_tester_.ExpectBucketCount(
kSandboxUnpackFailureReason,
SandboxedUnpackerFailureReason::CRX_HEADER_INVALID, 1);
histogram_tester_.ExpectBucketCount(kCrxHeaderInvalidFailureIsCWS, true, 1);
histogram_tester_.ExpectBucketCount(kCrxHeaderInvalidFailureFromCache, false,
1);
}
// Verifies that offstore extension that is downloaded from the update server
// and fails with CRX_HEADER_INVALID error is considered as a misconfiguration.
TEST_F(ForceInstalledMetricsTest,
ExtensionsCrxHeaderInvalidIsMisconfiguration) {
SetupForceList(false);
install_stage_tracker()->ReportDownloadingCacheStatus(
kExtensionId1, ExtensionDownloaderDelegate::CacheStatus::CACHE_MISS);
install_stage_tracker()->ReportSandboxedUnpackerFailureReason(
kExtensionId1,
CrxInstallError(SandboxedUnpackerFailureReason::CRX_HEADER_INVALID,
base::string16()));
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::PENDING);
registry()->AddEnabled(ext2.get());
force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kSandboxUnpackFailureReason, 1);
histogram_tester_.ExpectBucketCount(
kSandboxUnpackFailureReason,
SandboxedUnpackerFailureReason::CRX_HEADER_INVALID, 1);
histogram_tester_.ExpectBucketCount(kCrxHeaderInvalidFailureIsCWS, false, 1);
histogram_tester_.ExpectBucketCount(kCrxHeaderInvalidFailureFromCache, false,
1);
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
1);
}
// Reporting info when the force installed extension fails to install with error
// CRX_FETCH_URL_EMPTY due to no updates from the server.
TEST_F(ForceInstalledMetricsTest, ExtensionsNoUpdatesInfoReporting) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportInfoOnNoUpdatesFailure(kExtensionId1,
"disabled by client");
install_stage_tracker()->ReportFailure(
kExtensionId1, InstallStageTracker::FailureReason::CRX_FETCH_URL_EMPTY);
install_stage_tracker()->ReportInfoOnNoUpdatesFailure(kExtensionId2, "");
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::CRX_FETCH_URL_EMPTY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kManifestNoUpdatesInfo, 2);
histogram_tester_.ExpectBucketCount(
kManifestNoUpdatesInfo, InstallStageTracker::NoUpdatesInfo::kEmpty, 1);
histogram_tester_.ExpectBucketCount(
kManifestNoUpdatesInfo,
InstallStageTracker::NoUpdatesInfo::kDisabledByClient, 1);
}
// Regression test to check if the metrics are collected properly for the
// extensions which are already installed and loaded and then fail with error
// ALREADY_INSTALLED.
TEST_F(ForceInstalledMetricsTest,
ExtensionLoadedThenFailedWithAlreadyInstalledError) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId1, InstallStageTracker::FailureReason::ALREADY_INSTALLED);
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::LOADED);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 1);
histogram_tester_.ExpectTotalCount(kTimedOutStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutNotInstalledStats, 0);
}
// Regression test to check if the metrics are collected properly for the
// extensions which are in state READY. Also verifies that the failure reported
// after READY state is not reflected in the statistics.
TEST_F(ForceInstalledMetricsTest, ExtensionsReady) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::READY);
install_stage_tracker()->ReportFailure(
kExtensionId1, InstallStageTracker::FailureReason::ALREADY_INSTALLED);
scoped_refptr<const Extension> ext2 = CreateNewExtension(
kExtensionName2, kExtensionId2, ExtensionStatus::READY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 1);
histogram_tester_.ExpectTotalCount(kReadyTimeStats, 1);
histogram_tester_.ExpectTotalCount(kTimedOutStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutNotInstalledStats, 0);
histogram_tester_.ExpectTotalCount(kFailureReasonsCWS, 0);
}
// Regression test to check if no metrics are reported for READY state when some
// extensions are failed.
TEST_F(ForceInstalledMetricsTest, AllExtensionsNotReady) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::READY);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::INVALID_ID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectTotalCount(kReadyTimeStats, 0);
histogram_tester_.ExpectBucketCount(
kFailureReasonsCWS, InstallStageTracker::FailureReason::INVALID_ID, 1);
}
// Verifies that the installation stage is not overwritten by a previous stage.
TEST_F(ForceInstalledMetricsTest,
ExtensionsPreviousInstallationStageReportedAgain) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::CREATED);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::PENDING);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::CREATED);
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectUniqueSample(
kFailureReasonsCWS, InstallStageTracker::FailureReason::IN_PROGRESS, 1);
histogram_tester_.ExpectBucketCount(kInstallationStages,
InstallStageTracker::Stage::PENDING, 1);
}
// Verifies that the installation stage is overwritten if DOWNLOADING stage is
// reported again after INSTALLING stage.
TEST_F(ForceInstalledMetricsTest, ExtensionsDownloadingStageReportedAgain) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::DOWNLOADING);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::INSTALLING);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::DOWNLOADING);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId2, ExtensionDownloaderDelegate::Stage::PENDING);
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectUniqueSample(
kFailureReasonsCWS, InstallStageTracker::FailureReason::IN_PROGRESS, 1);
histogram_tester_.ExpectBucketCount(
kInstallationStages, InstallStageTracker::Stage::DOWNLOADING, 1);
}
TEST_F(ForceInstalledMetricsTest, ExtensionsStuck) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportInstallationStage(
kExtensionId1, InstallStageTracker::Stage::PENDING);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::DOWNLOADING);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId2, ExtensionDownloaderDelegate::Stage::PENDING);
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectUniqueSample(kTimedOutStats, 2, 1);
histogram_tester_.ExpectUniqueSample(kTimedOutNotInstalledStats, 2, 1);
histogram_tester_.ExpectUniqueSample(
kFailureReasonsCWS, InstallStageTracker::FailureReason::IN_PROGRESS, 2);
histogram_tester_.ExpectBucketCount(kInstallationStages,
InstallStageTracker::Stage::PENDING, 1);
histogram_tester_.ExpectBucketCount(
kInstallationStages, InstallStageTracker::Stage::DOWNLOADING, 1);
histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0);
histogram_tester_.ExpectUniqueSample(
kTotalCountStats,
prefs()->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1);
}
TEST_F(ForceInstalledMetricsTest, ExtensionStuckInCreatedStage) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::CREATED);
install_stage_tracker()->ReportInstallCreationStage(
kExtensionId2, InstallStageTracker::InstallCreationStage::
NOTIFIED_FROM_MANAGEMENT_INITIAL_CREATION_FORCED);
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectUniqueSample(
kFailureReasonsCWS, InstallStageTracker::FailureReason::IN_PROGRESS, 1);
histogram_tester_.ExpectUniqueSample(kInstallationStages,
InstallStageTracker::Stage::CREATED, 1);
histogram_tester_.ExpectUniqueSample(
kInstallCreationStages,
InstallStageTracker::InstallCreationStage::
NOTIFIED_FROM_MANAGEMENT_INITIAL_CREATION_FORCED,
1);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(ForceInstalledMetricsTest, ReportManagedGuestSessionOnExtensionFailure) {
chromeos::FakeChromeUserManager* fake_user_manager =
new chromeos::FakeChromeUserManager();
user_manager::ScopedUserManager scoped_user_manager(
base::WrapUnique(fake_user_manager));
const AccountId account_id =
AccountId::FromUserEmail(profile()->GetProfileUserName());
user_manager::User* user =
fake_user_manager->AddPublicAccountUser(account_id);
fake_user_manager->UserLoggedIn(account_id, user->username_hash(),
false /* browser_restart */,
false /* is_child */);
chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportFailure(
kExtensionId1, InstallStageTracker::FailureReason::INVALID_ID);
install_stage_tracker()->ReportCrxInstallError(
kExtensionId2,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_OTHER,
CrxInstallErrorDetail::UNEXPECTED_ID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(
kFailureSessionStats,
ForceInstalledMetrics::UserType::USER_TYPE_PUBLIC_ACCOUNT, 2);
}
TEST_F(ForceInstalledMetricsTest, ReportGuestSessionOnExtensionFailure) {
chromeos::FakeChromeUserManager* fake_user_manager =
new chromeos::FakeChromeUserManager();
user_manager::ScopedUserManager scoped_user_manager(
base::WrapUnique(fake_user_manager));
const AccountId account_id =
AccountId::FromUserEmail(profile()->GetProfileUserName());
user_manager::User* user = fake_user_manager->AddGuestUser();
fake_user_manager->UserLoggedIn(account_id, user->username_hash(),
false /* browser_restart */,
false /* is_child */);
chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportFailure(
kExtensionId1, InstallStageTracker::FailureReason::INVALID_ID);
install_stage_tracker()->ReportCrxInstallError(
kExtensionId2,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_OTHER,
CrxInstallErrorDetail::UNEXPECTED_ID);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(
kFailureSessionStats, ForceInstalledMetrics::UserType::USER_TYPE_GUEST,
2);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(ForceInstalledMetricsTest, ExtensionsAreDownloading) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportInstallationStage(
kExtensionId1, InstallStageTracker::Stage::DOWNLOADING);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId1, ExtensionDownloaderDelegate::Stage::DOWNLOADING_MANIFEST);
install_stage_tracker()->ReportInstallationStage(
kExtensionId2, InstallStageTracker::Stage::DOWNLOADING);
install_stage_tracker()->ReportDownloadingStage(
kExtensionId2, ExtensionDownloaderDelegate::Stage::DOWNLOADING_CRX);
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectUniqueSample(kTimedOutStats, 2, 1);
histogram_tester_.ExpectUniqueSample(kTimedOutNotInstalledStats, 2, 1);
histogram_tester_.ExpectUniqueSample(
kFailureReasonsCWS, InstallStageTracker::FailureReason::IN_PROGRESS, 2);
histogram_tester_.ExpectUniqueSample(
kInstallationStages, InstallStageTracker::Stage::DOWNLOADING, 2);
histogram_tester_.ExpectTotalCount(kInstallationDownloadingStages, 2);
histogram_tester_.ExpectBucketCount(
kInstallationDownloadingStages,
ExtensionDownloaderDelegate::Stage::DOWNLOADING_MANIFEST, 1);
histogram_tester_.ExpectBucketCount(
kInstallationDownloadingStages,
ExtensionDownloaderDelegate::Stage::DOWNLOADING_CRX, 1);
histogram_tester_.ExpectUniqueSample(
kTotalCountStats,
prefs()->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1);
}
// Error Codes in case of CRX_FETCH_FAILED.
TEST_F(ForceInstalledMetricsTest, ExtensionCrxFetchFailed) {
SetupForceList(true /*is_from_store */);
ExtensionDownloaderDelegate::FailureData data1(net::Error::OK, kResponseCode,
kFetchTries);
ExtensionDownloaderDelegate::FailureData data2(
-net::Error::ERR_INVALID_ARGUMENT, kFetchTries);
install_stage_tracker()->ReportFetchError(
kExtensionId1, InstallStageTracker::FailureReason::CRX_FETCH_FAILED,
data1);
install_stage_tracker()->ReportFetchError(
kExtensionId2, InstallStageTracker::FailureReason::CRX_FETCH_FAILED,
data2);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kNetworkErrorCodeStats, net::Error::OK,
1);
histogram_tester_.ExpectBucketCount(kHttpErrorCodeStats, kResponseCode, 1);
histogram_tester_.ExpectBucketCount(kNetworkErrorCodeStats,
-net::Error::ERR_INVALID_ARGUMENT, 1);
histogram_tester_.ExpectBucketCount(kFetchRetriesStats, kFetchTries, 2);
}
// Error Codes in case of MANIFEST_FETCH_FAILED.
TEST_F(ForceInstalledMetricsTest, ExtensionManifestFetchFailed) {
SetupForceList(true /*is_from_store */);
ExtensionDownloaderDelegate::FailureData data1(net::Error::OK, kResponseCode,
kFetchTries);
ExtensionDownloaderDelegate::FailureData data2(
-net::Error::ERR_INVALID_ARGUMENT, kFetchTries);
install_stage_tracker()->ReportFetchError(
kExtensionId1, InstallStageTracker::FailureReason::MANIFEST_FETCH_FAILED,
data1);
install_stage_tracker()->ReportFetchError(
kExtensionId2, InstallStageTracker::FailureReason::MANIFEST_FETCH_FAILED,
data2);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kNetworkErrorCodeManifestFetchFailedStats,
net::Error::OK, 1);
histogram_tester_.ExpectBucketCount(kHttpErrorCodeManifestFetchFailedStats,
kResponseCode, 1);
histogram_tester_.ExpectBucketCount(kNetworkErrorCodeManifestFetchFailedStats,
-net::Error::ERR_INVALID_ARGUMENT, 1);
histogram_tester_.ExpectBucketCount(kFetchRetriesManifestFetchFailedStats,
kFetchTries, 2);
}
// Errors occurred because the fetched update manifest was invalid.
TEST_F(ForceInstalledMetricsTest, ExtensionManifestInvalid) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportManifestInvalidFailure(
kExtensionId2,
ExtensionDownloaderDelegate::FailureData(
ManifestInvalidError::INVALID_PROTOCOL_ON_GUPDATE_TAG));
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectUniqueSample(
kExtensionManifestInvalid,
ManifestInvalidError::INVALID_PROTOCOL_ON_GUPDATE_TAG, 1);
}
// Errors occurred because the fetched update manifest was invalid because app
// status was not OK. Verifies that this error with app status error as
// "error-unknownApplication" is considered as a misconfiguration.
TEST_F(ForceInstalledMetricsTest, ExtensionManifestInvalidAppStatusError) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportManifestInvalidFailure(
kExtensionId2,
ExtensionDownloaderDelegate::FailureData(
ManifestInvalidError::BAD_APP_STATUS, "error-unknownApplication"));
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectUniqueSample(kExtensionManifestInvalid,
ManifestInvalidError::BAD_APP_STATUS, 1);
histogram_tester_.ExpectUniqueSample(
kExtensionManifestInvalidAppStatusError,
InstallStageTracker::AppStatusError::kErrorUnknownApplication, 1);
// Verify that the session with either all the extensions installed
// successfully, or all failures as admin-side misconfigurations is recorded
// here and BAD_APP_STATUS error is considered as a misconfiguration.
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
1);
}
// Session in which either all the extensions installed successfully, or all
// failures are admin-side misconfigurations. This test verifies that failure
// CRX_INSTALL_ERROR with detailed error KIOSK_MODE_ONLY is considered as
// misconfiguration.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailureNotPresentKioskModeOnlyError) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportCrxInstallError(
kExtensionId2,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_DECLINED,
CrxInstallErrorDetail::KIOSK_MODE_ONLY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
1);
}
// Session in which either all the extensions installed successfully, or all
// failures are admin-side misconfigurations. This test verifies that failure
// CRX_INSTALL_ERROR with detailed error DISALLOWED_BY_POLICY and when extension
// type which is not allowed to install according to policy
// kExtensionAllowedTypes is considered as misconfiguration.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailureNotPresentDisallowedByPolicyTypeError) {
SetupForceList(true /*is_from_store */);
// Set TYPE_EXTENSION and TYPE_THEME as the allowed extension types.
std::unique_ptr<base::Value> list =
ListBuilder().Append("extension").Append("theme").Build();
prefs()->SetManagedPref(pref_names::kAllowedTypes, std::move(list));
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
// Hosted app is not a valid extension type, so this should report an error.
install_stage_tracker()->ReportExtensionType(kExtensionId2,
Manifest::Type::TYPE_HOSTED_APP);
install_stage_tracker()->ReportCrxInstallError(
kExtensionId2,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_DECLINED,
CrxInstallErrorDetail::DISALLOWED_BY_POLICY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(
kPossibleNonMisconfigurationFailures,
0 /*Misconfiguration failure not present*/, 1 /*Count of the sample*/);
}
// Session in which at least one non misconfiguration failure occurred. One of
// the extension fails to install with DISALLOWED_BY_POLICY error but has
// extension type which is allowed by policy ExtensionAllowedTypes. This is not
// a misconfiguration failure.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailurePresentDisallowedByPolicyError) {
SetupForceList(true /*is_from_store */);
// Set TYPE_EXTENSION and TYPE_THEME as the allowed extension types.
std::unique_ptr<base::Value> list =
ListBuilder().Append("extension").Append("theme").Build();
prefs()->SetManagedPref(pref_names::kAllowedTypes, std::move(list));
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportExtensionType(kExtensionId2,
Manifest::Type::TYPE_EXTENSION);
install_stage_tracker()->ReportCrxInstallError(
kExtensionId2,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_DECLINED,
CrxInstallErrorDetail::DISALLOWED_BY_POLICY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures,
1 /*Misconfiguration failure present*/,
1 /*Count of the sample*/);
}
// Session in which at least one non misconfiguration failure occurred.
// Misconfiguration failure includes error KIOSK_MODE_ONLY, when force installed
// extension fails to install with failure reason CRX_INSTALL_ERROR.
TEST_F(ForceInstalledMetricsTest, NonMisconfigurationFailurePresent) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportFailure(
kExtensionId1, InstallStageTracker::FailureReason::INVALID_ID);
install_stage_tracker()->ReportCrxInstallError(
kExtensionId2,
InstallStageTracker::FailureReason::CRX_INSTALL_ERROR_DECLINED,
CrxInstallErrorDetail::KIOSK_MODE_ONLY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 1,
1);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Session in which either all the extensions installed successfully, or all
// failures are admin-side misconfigurations. This test verifies that failure
// REPLACED_BY_ARC_APP is not considered as misconfiguration when ARC++ is
// enabled for the profile.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailureNotPresentReplacedByArcAppErrorArcEnabled) {
// Enable ARC++ for this profile.
prefs()->SetManagedPref(arc::prefs::kArcEnabled,
std::make_unique<base::Value>(true));
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::REPLACED_BY_ARC_APP);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
1);
}
// Session in which at least one non misconfiguration failure occurred. This
// test verifies that failure REPLACED_BY_ARC_APP is not considered as
// misconfiguration when ARC++ is disabled for the profile.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailureNotPresentReplacedByArcAppErrorArcDisabled) {
// Enable ARC++ for this profile.
prefs()->SetManagedPref(arc::prefs::kArcEnabled,
std::make_unique<base::Value>(false));
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::REPLACED_BY_ARC_APP);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 1,
1);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Session in which either all the extensions installed successfully, or all
// failures are admin-side misconfigurations. This test verifies that failure
// NOT_PERFORMING_NEW_INSTALL is considered as misconfiguration.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailureNotPresentNotPerformingNewInstallError) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportFailure(
kExtensionId2,
InstallStageTracker::FailureReason::NOT_PERFORMING_NEW_INSTALL);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
1);
}
// Session in which either all the extensions installed successfully, or all
// failures are admin-side misconfigurations. This test verifies that failure
// CRX_FETCH_URL_EMPTY with empty info field is considered as misconfiguration.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailureNotPresentCrxFetchUrlEmptyError) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportInfoOnNoUpdatesFailure(kExtensionId2, "");
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::CRX_FETCH_URL_EMPTY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
1);
}
// This test verifies that failure CRX_FETCH_URL_EMPTY with non empty info field
// is not considered as a misconfiguration.
TEST_F(ForceInstalledMetricsTest,
NonMisconfigurationFailurePresentCrxFetchUrlEmptyError) {
SetupForceList(true /*is_from_store */);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::LOADED);
install_stage_tracker()->ReportInfoOnNoUpdatesFailure(kExtensionId2,
"rate limit");
install_stage_tracker()->ReportFailure(
kExtensionId2, InstallStageTracker::FailureReason::CRX_FETCH_URL_EMPTY);
// ForceInstalledMetrics shuts down timer because all extension are either
// loaded or failed.
EXPECT_FALSE(fake_timer_->IsRunning());
histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
0);
}
TEST_F(ForceInstalledMetricsTest, NoExtensionsConfigured) {
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
histogram_tester_.ExpectTotalCount(kLoadTimeStats, 0);
histogram_tester_.ExpectTotalCount(kReadyTimeStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutStats, 0);
histogram_tester_.ExpectTotalCount(kTimedOutNotInstalledStats, 0);
histogram_tester_.ExpectTotalCount(kFailureReasonsCWS, 0);
histogram_tester_.ExpectTotalCount(kInstallationStages, 0);
histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0);
histogram_tester_.ExpectTotalCount(kTotalCountStats, 0);
}
TEST_F(ForceInstalledMetricsTest, CachedExtensions) {
SetupForceList(true /*is_from_store */);
install_stage_tracker()->ReportDownloadingCacheStatus(
kExtensionId1, ExtensionDownloaderDelegate::CacheStatus::CACHE_HIT);
install_stage_tracker()->ReportDownloadingCacheStatus(
kExtensionId2, ExtensionDownloaderDelegate::CacheStatus::CACHE_MISS);
scoped_refptr<const Extension> ext1 = CreateNewExtension(
kExtensionName1, kExtensionId1, ExtensionStatus::PENDING);
registry()->AddEnabled(ext1.get());
EXPECT_TRUE(fake_timer_->IsRunning());
fake_timer_->Fire();
// If an extension was installed successfully, don't mention it in statistics.
histogram_tester_.ExpectUniqueSample(
kInstallationFailureCacheStatus,
ExtensionDownloaderDelegate::CacheStatus::CACHE_MISS, 1);
}
} // namespace extensions