chromium/chrome/browser/metrics/family_user_metrics_provider_browsertest.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/metrics/family_user_metrics_provider.h"

#include <optional>

#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/guest_session_mixin.h"
#include "chrome/browser/ash/login/test/logged_in_user_mixin.h"
#include "chrome/browser/ash/login/test/scoped_policy_update.h"
#include "chrome/browser/ash/login/test/user_policy_mixin.h"
#include "chrome/browser/ash/policy/test_support/embedded_policy_test_server_mixin.h"
#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
#include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/fake_gaia_mixin.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "components/account_id/account_id.h"
#include "components/metrics/metrics_service.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "content/public/test/browser_test.h"
#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
#include "third_party/metrics_proto/system_profile.pb.h"

namespace {

constexpr char kSecondaryEDUEmail[] = "[email protected]";

// Returns the user type for the primary test account for logging in.
ash::LoggedInUserMixin::LogInType GetPrimaryLogInType(
    FamilyUserMetricsProvider::FamilyUserLogSegment log_segment) {
  switch (log_segment) {
    case FamilyUserMetricsProvider::FamilyUserLogSegment::kSupervisedUser:
    case FamilyUserMetricsProvider::FamilyUserLogSegment::kSupervisedStudent:
      return ash::LoggedInUserMixin::LogInType::kChild;
    case FamilyUserMetricsProvider::FamilyUserLogSegment::kStudentAtHome:
      return ash::LoggedInUserMixin::LogInType::kManaged;
    case FamilyUserMetricsProvider::FamilyUserLogSegment::kRegularUser:
    case FamilyUserMetricsProvider::FamilyUserLogSegment::kOther:
      return ash::LoggedInUserMixin::LogInType::kConsumer;
  }
}

void ProvideHistograms() {
  // The purpose of the below call is to avoid a DCHECK failure in an unrelated
  // metrics provider, in |FieldTrialsProvider::ProvideCurrentSessionData()|.
  metrics::SystemProfileProto system_profile_proto;
  g_browser_process->metrics_service()
      ->GetDelegatingProviderForTesting()
      ->ProvideSystemProfileMetricsWithLogCreationTime(base::TimeTicks::Now(),
                                                       &system_profile_proto);

  g_browser_process->metrics_service()
      ->GetDelegatingProviderForTesting()
      ->OnDidCreateMetricsLog();
}

}  // namespace

class FamilyUserMetricsProviderTest
    : public MixinBasedInProcessBrowserTest,
      public testing::WithParamInterface<
          FamilyUserMetricsProvider::FamilyUserLogSegment> {
 public:
  void SetUpInProcessBrowserTestFixture() override {
    MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();

    if (GetFamilyUserLogSegment() ==
        FamilyUserMetricsProvider::FamilyUserLogSegment::kStudentAtHome) {
      logged_in_user_mixin_.GetEmbeddedPolicyTestServerMixin()
          ->SetMetricsLogSegment(enterprise_management::PolicyData::K12);
    }
  }

 protected:
  FamilyUserMetricsProvider::FamilyUserLogSegment GetFamilyUserLogSegment()
      const {
    return GetParam();
  }

  ash::LoggedInUserMixin logged_in_user_mixin_{
      &mixin_host_, /*test_base=*/this, embedded_test_server(),
      GetPrimaryLogInType(GetFamilyUserLogSegment())};
};

IN_PROC_BROWSER_TEST_P(FamilyUserMetricsProviderTest, UserCategory) {
  base::HistogramTester histogram_tester;
  // Simulate calling ProvideHistograms() prior to logging in. This call should
  // return prematurely.
  ProvideHistograms();

  // No metrics were recorded.
  histogram_tester.ExpectTotalCount(
      FamilyUserMetricsProvider::
          GetFamilyUserLogSegmentHistogramNameForTesting(),
      0);
  histogram_tester.ExpectTotalCount(
      FamilyUserMetricsProvider::
          GetNumSecondaryAccountsHistogramNameForTesting(),
      0);

  logged_in_user_mixin_.LogInUser();
  signin::WaitForRefreshTokensLoaded(
      IdentityManagerFactory::GetForProfile(browser()->profile()));

  if (GetFamilyUserLogSegment() ==
      FamilyUserMetricsProvider::FamilyUserLogSegment::kSupervisedStudent) {
    // Add a secondary EDU account.
    Profile* profile = browser()->profile();
    ASSERT_TRUE(profile);
    signin::IdentityManager* identity_manager =
        IdentityManagerFactory::GetForProfile(profile);
    AccountInfo account_info =
        signin::MakeAccountAvailable(identity_manager, kSecondaryEDUEmail);
    EXPECT_TRUE(
        identity_manager->HasAccountWithRefreshToken(account_info.account_id));
  }

  // Simulate calling ProvideHistograms() after logging in.
  ProvideHistograms();

  histogram_tester.ExpectUniqueSample(
      FamilyUserMetricsProvider::
          GetFamilyUserLogSegmentHistogramNameForTesting(),
      GetFamilyUserLogSegment(), /*expected_count=*/1);

  int expected_num_secondary_accounts =
      GetFamilyUserLogSegment() == FamilyUserMetricsProvider::
                                       FamilyUserLogSegment::kSupervisedStudent
          ? 1
          : 0;
  histogram_tester.ExpectUniqueSample(
      FamilyUserMetricsProvider::
          GetNumSecondaryAccountsHistogramNameForTesting(),
      expected_num_secondary_accounts, /*expected_count=*/1);
}

INSTANTIATE_TEST_SUITE_P(
    ,
    FamilyUserMetricsProviderTest,
    testing::Values(
        FamilyUserMetricsProvider::FamilyUserLogSegment::kSupervisedUser,
        FamilyUserMetricsProvider::FamilyUserLogSegment::kSupervisedStudent,
        FamilyUserMetricsProvider::FamilyUserLogSegment::kStudentAtHome,
        FamilyUserMetricsProvider::FamilyUserLogSegment::kRegularUser));

class FamilyUserMetricsProviderGuestModeTest
    : public MixinBasedInProcessBrowserTest {
 private:
  ash::GuestSessionMixin guest_session_mixin_{&mixin_host_};
};

// Prevents a regression to crbug/1137352. Also tests secondary account metrics
// not reported in guest mode.
IN_PROC_BROWSER_TEST_F(FamilyUserMetricsProviderGuestModeTest,
                       NoCrashInGuestMode) {
  base::HistogramTester histogram_tester;

  ProvideHistograms();

  histogram_tester.ExpectUniqueSample(
      FamilyUserMetricsProvider::
          GetFamilyUserLogSegmentHistogramNameForTesting(),
      FamilyUserMetricsProvider::FamilyUserLogSegment::kOther,
      /*expected_count=*/1);
  histogram_tester.ExpectTotalCount(
      FamilyUserMetricsProvider::
          GetNumSecondaryAccountsHistogramNameForTesting(),
      /*expected_count=*/0);
}

class FamilyUserMetricsProviderEphemeralUserTest
    : public MixinBasedInProcessBrowserTest {
 protected:
  // MixinBasedInProcessBrowserTest:
  void SetUpInProcessBrowserTestFixture() override {
    MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
    std::unique_ptr<ash::ScopedDevicePolicyUpdate> device_policy_update =
        device_state_.RequestDevicePolicyUpdate();
    device_policy_update->policy_payload()
        ->mutable_ephemeral_users_enabled()
        ->set_ephemeral_users_enabled(true);

    device_policy_update.reset();

    scoped_testing_cros_settings_.device_settings()->SetBoolean(
        ash::kReportDeviceLoginLogout, false);
  }

  // MixinBasedInProcessBrowserTest:
  void SetUpOnMainThread() override {
    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
    logged_in_user_mixin_.LogInUser();
    signin::WaitForRefreshTokensLoaded(
        IdentityManagerFactory::GetForProfile(browser()->profile()));
  }

  ash::DeviceStateMixin device_state_{
      &mixin_host_,
      ash::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};

  ash::LoggedInUserMixin logged_in_user_mixin_{
      &mixin_host_, /*test_base=*/this, embedded_test_server(),
      ash::LoggedInUserMixin::LogInType::kConsumer};

  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
};

// Tests that regular ephemeral users report 0 for number of secondary accounts.
IN_PROC_BROWSER_TEST_F(FamilyUserMetricsProviderEphemeralUserTest,
                       EphemeralUserZeroSecondaryAccounts) {
  base::HistogramTester histogram_tester;

  ProvideHistograms();

  histogram_tester.ExpectUniqueSample(
      FamilyUserMetricsProvider::
          GetFamilyUserLogSegmentHistogramNameForTesting(),
      FamilyUserMetricsProvider::FamilyUserLogSegment::kRegularUser,
      /*expected_count=*/1);
  histogram_tester.ExpectUniqueSample(
      FamilyUserMetricsProvider::
          GetNumSecondaryAccountsHistogramNameForTesting(),
      /*sample=*/0,
      /*expected_count=*/1);
}