chromium/chrome/browser/ash/child_accounts/family_user_device_metrics_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/ash/child_accounts/family_user_device_metrics.h"

#include <memory>
#include <optional>
#include <tuple>

#include "base/memory/raw_ptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/ash/login/test/device_state_mixin.h"
#include "chrome/browser/ash/login/test/logged_in_user_mixin.h"
#include "chrome/browser/ash/login/test/login_manager_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/login/users/fake_chrome_user_manager.h"
#include "components/account_id/account_id.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_type.h"
#include "content/public/test/browser_test.h"

namespace ash {

namespace {
const AccountId kDefaultOwnerAccountId =
    AccountId::FromUserEmailGaiaId(test::kTestEmail, test::kTestGaiaId);
const AccountId kManagedUserAccountId =
    AccountId::FromUserEmail("[email protected]");
const AccountId kActiveDirectoryUserAccountId =
    AccountId::AdFromUserEmailObjGuid("[email protected]", "obj-guid");
}  // namespace

// Test params:
//  - LogInType: regular or child.
//  - IsUserExisting: if false, no existing users on the login screen.
class FamilyUserDeviceMetricsTest
    : public MixinBasedInProcessBrowserTest,
      public testing::WithParamInterface<
          std::tuple<LoggedInUserMixin::LogInType, /*IsUserExisting=*/bool>> {
 protected:
  bool IsUserChild() const {
    return GetLogInType() == LoggedInUserMixin::LogInType::kChild;
  }
  bool IsUserExisting() const { return std::get<1>(GetParam()); }

  raw_ptr<FakeChromeUserManager, DanglingUntriaged> user_manager_ = nullptr;

  LoggedInUserMixin logged_in_user_mixin_{
      &mixin_host_, /*test_base=*/this, embedded_test_server(), GetLogInType(),
      /*include_initial_user=*/IsUserExisting()};

  // MixinBasedInProcessBrowserTest:
  void SetUpInProcessBrowserTestFixture() override {
    if (IsUserExisting()) {
      // Append another user of the same type.
      if (IsUserChild()) {
        logged_in_user_mixin_.GetLoginManagerMixin()->AppendChildUsers(1);
      } else {
        logged_in_user_mixin_.GetLoginManagerMixin()->AppendRegularUsers(1);
      }
    }
    MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
  }

  void SetUpOnMainThread() override {
    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
    // Child users require user policy. Set up an empty one so the user can get
    // through login.
    user_policy_mixin_.RequestPolicyUpdate();
    user_manager_ =
        static_cast<FakeChromeUserManager*>(user_manager::UserManager::Get());
  }

 private:
  LoggedInUserMixin::LogInType GetLogInType() const {
    return std::get<0>(GetParam());
  }

  UserPolicyMixin user_policy_mixin_{&mixin_host_, kDefaultOwnerAccountId};
};

// TODO(crbug.com/40892366): Test is flaky. Too many histogram entries are
// sometimes generated.
#define MAYBE_IsDeviceOwner DISABLED_IsDeviceOwner
IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsTest, MAYBE_IsDeviceOwner) {
  base::HistogramTester histogram_tester;

  // Set the device owner to the logged in user.
  user_manager_->SetOwnerId(logged_in_user_mixin_.GetAccountId());
  logged_in_user_mixin_.LogInUser(
      {ash::LoggedInUserMixin::LoginDetails::kNoBrowserLaunch});

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetDeviceOwnerHistogramNameForTest(),
      /*sample=*/true, /*expected_count=*/1);
}

// TODO(crbug.com/40892366): Test is flaky. Too many histogram entries are
// sometimes generated.
#define MAYBE_IsNotDeviceOwner DISABLED_IsNotDeviceOwner
IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsTest, MAYBE_IsNotDeviceOwner) {
  base::HistogramTester histogram_tester;

  // Set the device owner to an arbitrary account that's not logged in.
  user_manager_->SetOwnerId(kDefaultOwnerAccountId);
  logged_in_user_mixin_.LogInUser(
      {ash::LoggedInUserMixin::LoginDetails::kNoBrowserLaunch});

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetDeviceOwnerHistogramNameForTest(),
      /*sample=*/false, /*expected_count=*/1);
}

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsTest, SingleUserAdded) {
  base::HistogramTester histogram_tester;

  logged_in_user_mixin_.LogInUser(
      {ash::LoggedInUserMixin::LoginDetails::kNoBrowserLaunch});

  if (IsUserExisting()) {
    // This user has signed into this device before, so they are not new.
    histogram_tester.ExpectTotalCount(
        FamilyUserDeviceMetrics::GetNewUserAddedHistogramNameForTest(), 0);
  } else {
    // This is the first time this user is signing into this device.
    FamilyUserDeviceMetrics::NewUserAdded sample =
        IsUserChild()
            ? FamilyUserDeviceMetrics::NewUserAdded::kFamilyLinkUserAdded
            : FamilyUserDeviceMetrics::NewUserAdded::kRegularUserAdded;
    histogram_tester.ExpectUniqueSample(
        FamilyUserDeviceMetrics::GetNewUserAddedHistogramNameForTest(), sample,
        /*expected_count=*/1);
  }
}

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsTest, SingleUserCount) {
  if (!IsUserExisting()) {
    GTEST_SKIP() << "This test makes sense only for existing user";
  }
  base::HistogramTester histogram_tester;

  logged_in_user_mixin_.LogInUser(
      {ash::LoggedInUserMixin::LoginDetails::kNoBrowserLaunch});

  // Current user + extra user from setup.
  const int gaia_users_count = 2;
  const int family_link_users_count = IsUserChild() ? gaia_users_count : 0;

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetFamilyLinkUsersCountHistogramNameForTest(),
      /*sample=*/family_link_users_count,
      /*expected_count=*/1);
  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/gaia_users_count,
      /*expected_count=*/1);
}

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsTest, LoginAsNewChildUser) {
  if (IsUserExisting() && !IsUserChild()) {
    GTEST_SKIP() << "As this test runs LoginAsNewChildUser"
                    " it is expected that if user exists, it is a child user";
  }
  base::HistogramTester histogram_tester;

  logged_in_user_mixin_.GetLoginManagerMixin()->SkipPostLoginScreens();
  logged_in_user_mixin_.GetLoginManagerMixin()->LoginAsNewChildUser();
  logged_in_user_mixin_.GetLoginManagerMixin()->WaitForActiveSession();

  // If existing Family Link user on login screen, then two Family Link users.
  const int family_link_users_count = IsUserExisting() && IsUserChild() ? 2 : 1;
  // If no existing users on login screen, then this user is the first and only.
  const int gaia_users_count = IsUserExisting() ? 2 : 1;
  // If user existed before, then no users were added.
  const int family_link_users_added = IsUserExisting() ? 0 : 1;

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetNewUserAddedHistogramNameForTest(),
      FamilyUserDeviceMetrics::NewUserAdded::kFamilyLinkUserAdded,
      /*expected_count=*/family_link_users_added);
  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetFamilyLinkUsersCountHistogramNameForTest(),
      /*sample=*/family_link_users_count,
      /*expected_count=*/1);
  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics ::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/gaia_users_count,
      /*expected_count=*/1);
}

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsTest, LoginAsNewRegularUser) {
  base::HistogramTester histogram_tester;

  logged_in_user_mixin_.GetLoginManagerMixin()->SkipPostLoginScreens();
  logged_in_user_mixin_.GetLoginManagerMixin()->LoginAsNewRegularUser();
  logged_in_user_mixin_.GetLoginManagerMixin()->WaitForActiveSession();

  // If existing Family Link user on login screen, then one Family Link user.
  const int family_link_users_count = IsUserExisting() && IsUserChild() ? 1 : 0;
  // If no existing users on login screen, then this user is the first and only.
  const int gaia_users_count = IsUserExisting() ? 2 : 1;
  // If user existed before, then no users were added.
  const int regular_users_added = IsUserExisting() ? 0 : 1;

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetNewUserAddedHistogramNameForTest(),
      FamilyUserDeviceMetrics::NewUserAdded::kRegularUserAdded,
      /*expected_count=*/regular_users_added);
  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetFamilyLinkUsersCountHistogramNameForTest(),
      /*sample=*/family_link_users_count,
      /*expected_count=*/1);
  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/gaia_users_count,
      /*expected_count=*/1);
}

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsTest, GuestUser) {
  base::HistogramTester histogram_tester;

  user_manager_->AddGuestUser();

  logged_in_user_mixin_.GetLoginManagerMixin()->SkipPostLoginScreens();
  logged_in_user_mixin_.GetLoginManagerMixin()->LoginAsNewRegularUser();
  logged_in_user_mixin_.GetLoginManagerMixin()->WaitForActiveSession();

  size_t total_user_count = IsUserExisting() ? 3 : 2;
  EXPECT_EQ(total_user_count, user_manager_->GetUsers().size());

  // If no existing users on login screen, then this user is the first and only.
  const int gaia_users_count = IsUserExisting() ? 2 : 1;

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/gaia_users_count,
      /*expected_count=*/1);
}

INSTANTIATE_TEST_SUITE_P(
    ,
    FamilyUserDeviceMetricsTest,
    testing::Combine(testing::Values(LoggedInUserMixin::LogInType::kChild,
                                     LoggedInUserMixin::LogInType::kConsumer),
                     /*IsUserExisting=*/testing::Bool()));

class FamilyUserDeviceMetricsManagedDeviceTest
    : public FamilyUserDeviceMetricsTest {
 protected:
  void LoginAsNewRegularUser() {
    logged_in_user_mixin_.GetLoginManagerMixin()->SkipPostLoginScreens();
    logged_in_user_mixin_.GetLoginManagerMixin()->LoginAsNewRegularUser();
    logged_in_user_mixin_.GetLoginManagerMixin()->WaitForActiveSession();
  }

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

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsManagedDeviceTest, KioskAppUser) {
  base::HistogramTester histogram_tester;

  user_manager_->AddKioskAppUser(kManagedUserAccountId);
  LoginAsNewRegularUser();

  size_t total_user_count = IsUserExisting() ? 3 : 2;
  EXPECT_EQ(total_user_count, user_manager_->GetUsers().size());

  // If no existing users on login screen, then this user is the first and only.
  const int gaia_users_count = IsUserExisting() ? 2 : 1;

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/gaia_users_count,
      /*expected_count=*/1);
}

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsManagedDeviceTest,
                       WebKioskAppUser) {
  base::HistogramTester histogram_tester;

  user_manager_->AddWebKioskAppUser(kManagedUserAccountId);
  LoginAsNewRegularUser();

  size_t total_user_count = IsUserExisting() ? 3 : 2;
  EXPECT_EQ(total_user_count, user_manager_->GetUsers().size());

  // If no existing users on login screen, then this user is the first and only.
  const int gaia_users_count = IsUserExisting() ? 2 : 1;

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/gaia_users_count,
      /*expected_count=*/1);
}

IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsManagedDeviceTest,
                       PublicAccountUser) {
  base::HistogramTester histogram_tester;

  user_manager_->AddPublicAccountUser(kManagedUserAccountId);
  LoginAsNewRegularUser();

  size_t total_user_count = IsUserExisting() ? 3 : 2;
  EXPECT_EQ(total_user_count, user_manager_->GetUsers().size());

  // If no existing users on login screen, then this user is the first and only.
  const int gaia_users_count = IsUserExisting() ? 2 : 1;

  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/gaia_users_count,
      /*expected_count=*/1);
}

INSTANTIATE_TEST_SUITE_P(
    ,
    FamilyUserDeviceMetricsManagedDeviceTest,
    testing::Combine(testing::Values(LoggedInUserMixin::LogInType::kChild,
                                     LoggedInUserMixin::LogInType::kConsumer),
                     /*IsUserExisting=*/testing::Bool()));

class FamilyUserDeviceMetricsEphemeralUserTest
    : public FamilyUserDeviceMetricsManagedDeviceTest {
 protected:
  // MixinBaseInProcessBrowserTest:
  void SetUpInProcessBrowserTestFixture() override {
    MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
    std::unique_ptr<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();
  }
};

// Tests that regular ephemeral users report 0 for FamilyUser.GaiaUsersCount.
IN_PROC_BROWSER_TEST_P(FamilyUserDeviceMetricsEphemeralUserTest,
                       EphemeralUser) {
  base::HistogramTester histogram_tester;
  LoginAsNewRegularUser();
  histogram_tester.ExpectUniqueSample(
      FamilyUserDeviceMetrics::GetGaiaUsersCountHistogramNameForTest(),
      /*sample=*/0,
      /*expected_count=*/1);
}

INSTANTIATE_TEST_SUITE_P(
    ,
    FamilyUserDeviceMetricsEphemeralUserTest,
    testing::Combine(testing::Values(LoggedInUserMixin::LogInType::kChild,
                                     LoggedInUserMixin::LogInType::kConsumer),
                     /*IsUserExisting=*/testing::Values(false)));

}  // namespace ash