910e62b5创建于 1月15日历史提交
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/collaboration/internal/collaboration_service_impl.h"

#include <memory>

#include "base/android/device_info.h"
#include "base/test/run_until.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/collaboration/internal/collaboration_controller.h"
#include "components/collaboration/public/pref_names.h"
#include "components/collaboration/test_support/mock_collaboration_controller_delegate.h"
#include "components/data_sharing/public/data_sharing_service.h"
#include "components/data_sharing/public/features.h"
#include "components/data_sharing/test_support/mock_data_sharing_service.h"
#include "components/saved_tab_groups/test_support/mock_tab_group_sync_service.h"
#include "components/saved_tab_groups/test_support/saved_tab_group_test_utils.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/sync/base/features.h"
#include "components/sync/test/test_sync_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "google_apis/gaia/gaia_id.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using data_sharing::GroupData;
using data_sharing::GroupId;
using data_sharing::GroupMember;
using data_sharing::MemberRole;
using signin::PrimaryAccountChangeEvent;
using testing::_;
using testing::Return;

namespace collaboration {

namespace {

constexpr GaiaId::Literal kUserGaia("gaia_id");
constexpr GaiaId::Literal kOtherUserGaia("other_gaia_id");
constexpr char kConsumerUserEmail[] = "test@email.com";
constexpr char kOtherConsumerUserEmail[] = "other.test@email.com";
constexpr char kManagedUserEmail[] = "test@google.com";
constexpr char kGroupId[] = "/?-group_id";
constexpr char kAccessToken[] = "/?-access_token";

}  // namespace

class CollaborationServiceImplTest : public testing::Test {
 public:
  CollaborationServiceImplTest() = default;

  ~CollaborationServiceImplTest() override = default;

  void SetUp() override {
#if BUILDFLAG(IS_ANDROID)
    if (base::android::device_info::is_automotive()) {
      // TODO(crbug.com/399444939): Re-enable once automotive is supported.
      GTEST_SKIP() << "Test shouldn't run on automotive builders.";
    }
#endif
    test_sync_service_ = std::make_unique<syncer::TestSyncService>();
    profile_pref_service_.registry()->RegisterIntegerPref(
        prefs::kSharedTabGroupsManagedAccountSetting, 0 /* enabled */);
    profile_pref_service_.registry()->RegisterBooleanPref(
        ::prefs::kSigninAllowed, true);
    profile_pref_service_.registry()->RegisterBooleanPref(
        ::prefs::kSigninAllowedOnNextStartup, true);
#if BUILDFLAG(IS_IOS)
    local_pref_service_.registry()->RegisterIntegerPref(
        ::prefs::kBrowserSigninPolicy,
        static_cast<int>(BrowserSigninMode::kEnabled));
#endif
    InitService();
  }

  void TearDown() override { service_.reset(); }

  void InitService() {
    service_ = std::make_unique<CollaborationServiceImpl>(
        &mock_tab_group_sync_service_, &mock_data_sharing_service_,
        identity_test_env_.identity_manager(), &profile_pref_service_,
        &local_pref_service_);
    service_->OnSyncServiceInitialized(test_sync_service_.get());
  }

 protected:
  base::test::SingleThreadTaskEnvironment task_environment_;
  sync_preferences::TestingPrefServiceSyncable profile_pref_service_;
  sync_preferences::TestingPrefServiceSyncable local_pref_service_;
  signin::IdentityTestEnvironment identity_test_env_;
  std::unique_ptr<syncer::TestSyncService> test_sync_service_;
  tab_groups::MockTabGroupSyncService mock_tab_group_sync_service_;
  data_sharing::MockDataSharingService mock_data_sharing_service_;
  std::unique_ptr<CollaborationServiceImpl> service_;
};

TEST_F(CollaborationServiceImplTest, ConstructionAndEmptyServiceCheck) {
  EXPECT_FALSE(service_->IsEmptyService());
}

TEST_F(CollaborationServiceImplTest, GetCurrentUserRoleForGroup) {
  GroupData group_data = GroupData();
  GroupMember group_member = GroupMember();
  group_member.gaia_id = kUserGaia;
  group_member.role = MemberRole::kOwner;
  group_data.members.push_back(group_member);

  data_sharing::GroupId group_id = data_sharing::GroupId(kGroupId);

  // Empty or non existent group should return unknown role.
  EXPECT_CALL(mock_data_sharing_service_, ReadGroup(group_id))
      .WillOnce(Return(std::nullopt));

  EXPECT_EQ(service_->GetCurrentUserRoleForGroup(group_id),
            MemberRole::kUnknown);

  // No current primary account should return unknown role.
  EXPECT_CALL(mock_data_sharing_service_, ReadGroup(group_id))
      .WillRepeatedly(Return(group_data));
  EXPECT_EQ(service_->GetCurrentUserRoleForGroup(group_id),
            MemberRole::kUnknown);

  identity_test_env_.MakeAccountAvailable(
      kConsumerUserEmail,
      {.primary_account_consent_level = signin::ConsentLevel::kSignin,
       .gaia_id = kUserGaia});
  EXPECT_EQ(service_->GetCurrentUserRoleForGroup(group_id), MemberRole::kOwner);
}

TEST_F(CollaborationServiceImplTest, GetServiceStatus_Disabled) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures({},
                                {data_sharing::features::kDataSharingFeature,
                                 data_sharing::features::kDataSharingJoinOnly});
  InitService();

  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kDisabled);
}

TEST_F(CollaborationServiceImplTest, GetServiceStatus_JoinOnly) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures({data_sharing::features::kDataSharingJoinOnly},
                                {data_sharing::features::kDataSharingFeature});
  InitService();

  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kAllowedToJoin);
}

TEST_F(CollaborationServiceImplTest, GetServiceStatus_Create) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures({data_sharing::features::kDataSharingFeature},
                                {data_sharing::features::kDataSharingJoinOnly});
  InitService();

  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kEnabledCreateAndJoin);
}

TEST_F(CollaborationServiceImplTest, GetServiceStatus_CreateOverridesJoinOnly) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures({data_sharing::features::kDataSharingJoinOnly,
                                 data_sharing::features::kDataSharingFeature},
                                {});
  InitService();

  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kEnabledCreateAndJoin);
}

TEST_F(CollaborationServiceImplTest, GetServiceStatus_SigninDisabledByUser) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(
      data_sharing::features::kDataSharingFeature);

  // Set signin preference to disable signin.
  profile_pref_service_.SetBoolean(::prefs::kSigninAllowed, false);
  profile_pref_service_.SetBoolean(::prefs::kSigninAllowedOnNextStartup, false);

  InitService();

  EXPECT_EQ(service_->GetServiceStatus().signin_status,
            SigninStatus::kSigninDisabled);
  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kEnabledCreateAndJoin);
  EXPECT_EQ(service_->GetServiceStatus().IsAllowedToJoin(), true);
  EXPECT_EQ(service_->GetServiceStatus().IsAllowedToCreate(), false);
}

#if !BUILDFLAG(IS_IOS)
TEST_F(CollaborationServiceImplTest, GetServiceStatus_SigninDisabledByPolicy) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(
      data_sharing::features::kDataSharingFeature);

#if BUILDFLAG(IS_ANDROID)
  profile_pref_service_.SetBoolean(::prefs::kSigninAllowed, false);
  profile_pref_service_.SetManagedPref(::prefs::kSigninAllowed,
                                       base::Value(false));
#else
  profile_pref_service_.SetBoolean(::prefs::kSigninAllowedOnNextStartup, false);
  profile_pref_service_.SetManagedPref(::prefs::kSigninAllowedOnNextStartup,
                                       base::Value(false));
#endif

  InitService();
  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kDisabledForPolicy);
}
#endif

TEST_F(CollaborationServiceImplTest, GetServiceStatus_ManagedAccount) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(
      data_sharing::features::kDataSharingFeature);
  InitService();
  profile_pref_service_.SetInteger(prefs::kSharedTabGroupsManagedAccountSetting,
                                   1 /* disabled */);

  EXPECT_EQ(service_->GetServiceStatus().signin_status,
            SigninStatus::kNotSignedIn);
  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kEnabledCreateAndJoin);

  // Signin a managed account.
  identity_test_env_.MakePrimaryAccountAvailable(kManagedUserEmail,
                                                 signin::ConsentLevel::kSignin);
  EXPECT_EQ(service_->GetServiceStatus().signin_status,
            SigninStatus::kSignedIn);
  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kDisabledForPolicy);

  // Signin a consumer account re-enable the feature.
  identity_test_env_.MakePrimaryAccountAvailable(kConsumerUserEmail,
                                                 signin::ConsentLevel::kSignin);
  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kEnabledCreateAndJoin);
}

TEST_F(CollaborationServiceImplTest, StartJoinFlow) {
  GURL url("http://www.example.com/");

  // Invalid url parsing starts a join flow with empty GroupToken.
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate_invalid =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_invalid_ptr =
      mock_delegate_invalid.get();
  EXPECT_CALL(*mock_delegate_invalid, OnFlowFinished());
  service_->StartJoinFlow(std::move(mock_delegate_invalid), url);
  // Wait for post tasks.
  EXPECT_TRUE(base::test::RunUntil(
      [&]() { return service_->GetJoinControllersForTesting().size() == 1; }));
  const std::map<data_sharing::GroupToken,
                 std::unique_ptr<CollaborationController>>& join_flows =
      service_->GetJoinControllersForTesting();
  EXPECT_TRUE(join_flows.find(data_sharing::GroupToken()) != join_flows.end());

  // New join flow will be appended with a valid url parsing and will stop all
  // conflicting flows.
  url = GURL(data_sharing::features::kDataSharingURL.Get() + "?g=" + kGroupId +
             "&t=" + kAccessToken);
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  EXPECT_CALL(*mock_delegate, OnFlowFinished());

  bool invalid_cancel_called = false;
  EXPECT_CALL(*delegate_invalid_ptr, Cancel(_))
      .WillOnce([&](CollaborationControllerDelegate::ResultCallback result) {
        invalid_cancel_called = true;
        std::move(result).Run(
            CollaborationControllerDelegate::Outcome::kSuccess);
        return true;
      });

  service_->StartJoinFlow(std::move(mock_delegate), url);

  // Wait for post tasks.
  EXPECT_TRUE(base::test::RunUntil(
      [&]() { return service_->GetJoinControllersForTesting().size() == 1; }));

  EXPECT_TRUE(invalid_cancel_called);

  bool cancel_called = false;
  EXPECT_CALL(*delegate_ptr, Cancel(_))
      .WillOnce([&](CollaborationControllerDelegate::ResultCallback result) {
        cancel_called = true;
        std::move(result).Run(
            CollaborationControllerDelegate::Outcome::kSuccess);
        return true;
      });

  // Existing join flow will stop all conflicting flows and will be appended
  // similar to a new join flow.
  service_->StartJoinFlow(
      std::make_unique<MockCollaborationControllerDelegate>(), url);
  EXPECT_EQ(service_->GetJoinControllersForTesting().size(), 1u);
  EXPECT_TRUE(cancel_called);
}

TEST_F(CollaborationServiceImplTest, SyncStatusChanges) {
  // By default the test sync service is signed in with sync and every DataType
  // enabled.
  EXPECT_EQ(service_->GetServiceStatus().sync_status, SyncStatus::kSyncEnabled);

  // Remove user's tab group setting.
  test_sync_service_->GetUserSettings()->SetSelectedTypes(
      /*sync_everything=*/false,
      /*types=*/{});
  test_sync_service_->FireStateChanged();
  EXPECT_EQ(service_->GetServiceStatus().sync_status,
            SyncStatus::kSyncWithoutTabGroup);

  if (base::FeatureList::IsEnabled(
          syncer::kReplaceSyncPromosWithSignInPromos)) {
    // If sync-the-feature is not required, kNotSyncing is never happening.
    test_sync_service_->SetSignedOut();
    test_sync_service_->FireStateChanged();
    EXPECT_EQ(service_->GetServiceStatus().sync_status,
              SyncStatus::kSyncWithoutTabGroup);
  } else {
    // Sign out removes sync consent.
    test_sync_service_->SetSignedOut();
    test_sync_service_->FireStateChanged();
    EXPECT_EQ(service_->GetServiceStatus().sync_status,
              SyncStatus::kNotSyncing);
  }
}

TEST_F(CollaborationServiceImplTest, SyncTypeDisabledByEnterprise) {
#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
  // Set up a policy to disable Tabs.
  test_sync_service_->GetUserSettings()->SetTypeIsManagedByPolicy(
      syncer::UserSelectableType::kTabs, true);
  test_sync_service_->FireStateChanged();
  EXPECT_EQ(service_->GetServiceStatus().sync_status,
            SyncStatus::kSyncDisabledByEnterprise);

  // Reset the policy.
  test_sync_service_->GetUserSettings()->SetTypeIsManagedByPolicy(
      syncer::UserSelectableType::kTabs, false);
  test_sync_service_->FireStateChanged();
  EXPECT_EQ(service_->GetServiceStatus().sync_status, SyncStatus::kSyncEnabled);

  // Set up a policy to disable History.
  test_sync_service_->GetUserSettings()->SetTypeIsManagedByPolicy(
      syncer::UserSelectableType::kHistory, true);
  test_sync_service_->FireStateChanged();
  EXPECT_EQ(service_->GetServiceStatus().sync_status,
            SyncStatus::kSyncDisabledByEnterprise);
#else
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(syncer::kReplaceSyncPromosWithSignInPromos);

  // Set up a policy to disable Saved Tab Groups.
  test_sync_service_->GetUserSettings()->SetTypeIsManagedByPolicy(
      syncer::UserSelectableType::kSavedTabGroups, true);
  test_sync_service_->FireStateChanged();
  EXPECT_EQ(service_->GetServiceStatus().sync_status,
            SyncStatus::kSyncDisabledByEnterprise);
#endif
}

TEST_F(CollaborationServiceImplTest, SyncDisabledByEnterprise) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(syncer::kReplaceSyncPromosWithSignInPromos);

  // Disable sync by enterprise policy.
  test_sync_service_->SetAllowedByEnterprisePolicy(false);
  test_sync_service_->FireStateChanged();
  EXPECT_EQ(service_->GetServiceStatus().sync_status,
            SyncStatus::kSyncDisabledByEnterprise);
}

TEST_F(CollaborationServiceImplTest, SyncStatusChanges_SettingInProgress) {
  // By default the test sync service is signed in with sync and every DataType
  // enabled.
  EXPECT_EQ(service_->GetServiceStatus().sync_status, SyncStatus::kSyncEnabled);

  // Setup in progress does not change sync status.
  test_sync_service_->SetSetupInProgress();
  test_sync_service_->SetSignedOut();
  test_sync_service_->FireStateChanged();
  EXPECT_EQ(service_->GetServiceStatus().sync_status, SyncStatus::kSyncEnabled);
}

TEST_F(CollaborationServiceImplTest, ConsumerSigninChanges) {
  EXPECT_EQ(service_->GetServiceStatus().signin_status,
            SigninStatus::kNotSignedIn);

  identity_test_env_.SetPrimaryAccount(kConsumerUserEmail,
                                       signin::ConsentLevel::kSignin);
  EXPECT_EQ(service_->GetServiceStatus().signin_status,
            SigninStatus::kSignedInPaused);

  identity_test_env_.SetRefreshTokenForPrimaryAccount();
  EXPECT_EQ(service_->GetServiceStatus().signin_status,
            SigninStatus::kSignedIn);
}

TEST_F(CollaborationServiceImplTest, DeleteGroup) {
  data_sharing::GroupId group_id = data_sharing::GroupId(kGroupId);
  EXPECT_CALL(mock_tab_group_sync_service_,
              OnCollaborationRemoved(syncer::CollaborationId(kGroupId)));
  EXPECT_CALL(mock_data_sharing_service_, DeleteGroup(group_id, _))
      .WillOnce(
          [](const data_sharing::GroupId&,
             base::OnceCallback<void(
                 data_sharing::DataSharingService::PeopleGroupActionOutcome)>
                 callback) {
            std::move(callback).Run(data_sharing::DataSharingService::
                                        PeopleGroupActionOutcome::kSuccess);
          });

  base::RunLoop run_loop;
  service_->DeleteGroup(group_id,
                        base::BindOnce(
                            [](base::RunLoop* run_loop, bool success) {
                              ASSERT_TRUE(success);
                              run_loop->Quit();
                            },
                            &run_loop));
  run_loop.Run();
}

TEST_F(CollaborationServiceImplTest, LeaveGroup) {
  data_sharing::GroupId group_id = data_sharing::GroupId(kGroupId);
  EXPECT_CALL(mock_tab_group_sync_service_,
              OnCollaborationRemoved(syncer::CollaborationId(kGroupId)));
  EXPECT_CALL(mock_data_sharing_service_, LeaveGroup(group_id, _))
      .WillOnce(
          [](const data_sharing::GroupId&,
             base::OnceCallback<void(
                 data_sharing::DataSharingService::PeopleGroupActionOutcome)>
                 callback) {
            std::move(callback).Run(data_sharing::DataSharingService::
                                        PeopleGroupActionOutcome::kSuccess);
          });

  base::RunLoop run_loop;
  service_->LeaveGroup(group_id, base::BindOnce(
                                     [](base::RunLoop* run_loop, bool success) {
                                       ASSERT_TRUE(success);
                                       run_loop->Quit();
                                     },
                                     &run_loop));
  run_loop.Run();
}

TEST_F(CollaborationServiceImplTest, CancelAllFlows) {
  GURL url = GURL(data_sharing::features::kDataSharingURL.Get() +
                  "?g=" + kGroupId + "&t=" + kAccessToken);

  // New join flow will be appended with a valid url parsing and will stop all
  // conflicting flows.
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  EXPECT_CALL(*mock_delegate, OnFlowFinished());
  service_->StartJoinFlow(std::move(mock_delegate), url);

  // Wait for post tasks.
  EXPECT_TRUE(base::test::RunUntil(
      [&]() { return service_->GetJoinControllersForTesting().size() == 1; }));

  bool cancel_called = false;
  EXPECT_CALL(*delegate_ptr, Cancel(_))
      .WillOnce([&](CollaborationControllerDelegate::ResultCallback result) {
        cancel_called = true;
        std::move(result).Run(
            CollaborationControllerDelegate::Outcome::kSuccess);
        return true;
      });
  service_->CancelAllFlows();

  EXPECT_TRUE(cancel_called);

  // Wait for post tasks.
  EXPECT_TRUE(service_->GetJoinControllersForTesting().size() == 0);
  EXPECT_TRUE(service_->GetDeletingControllersCountForTesting() == 1);
  EXPECT_TRUE(base::test::RunUntil([&]() {
    return service_->GetDeletingControllersCountForTesting() == 0;
  }));
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_NoChange_DoesntCancelJoin) {
  // Start a join flow.
  GURL url = GURL(data_sharing::features::kDataSharingURL.Get() +
                  "?g=" + kGroupId + "&t=" + kAccessToken);
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartJoinFlow(std::move(mock_delegate), url);
  EXPECT_CALL(*delegate_ptr, Cancel(_)).Times(0);
  // Prepare a kNoChange event.
  PrimaryAccountChangeEvent::State state;
  PrimaryAccountChangeEvent event_details(
      state, state, signin_metrics::AccessPoint::kUnknown);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_NoChange_DoesntCancelShare) {
  // Start a share flow.
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartShareOrManageFlow(
      std::move(mock_delegate), tab_groups::test::GenerateRandomTabGroupID(),
      CollaborationServiceShareOrManageEntryPoint::kUnknown);
  EXPECT_CALL(*delegate_ptr, Cancel(_)).Times(0);
  // Prepare a kNoChange event.
  PrimaryAccountChangeEvent::State state;
  PrimaryAccountChangeEvent event_details(
      state, state, signin_metrics::AccessPoint::kUnknown);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_SigningInFromUnsignedIn_DoesntCancelJoin) {
  // Start a join flow.
  GURL url = GURL(data_sharing::features::kDataSharingURL.Get() +
                  "?g=" + kGroupId + "&t=" + kAccessToken);
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartJoinFlow(std::move(mock_delegate), url);
  EXPECT_CALL(*delegate_ptr, Cancel(_)).Times(0);
  // Prepare a kSet event from unsigned in to signed in.
  PrimaryAccountChangeEvent::State previous_state;
  CoreAccountInfo account_info;
  account_info.gaia = kUserGaia;
  account_info.account_id = CoreAccountId::FromGaiaId(account_info.gaia);
  account_info.email = kConsumerUserEmail;
  PrimaryAccountChangeEvent::State current_state(account_info,
                                                 signin::ConsentLevel::kSignin);
  PrimaryAccountChangeEvent event_details(
      previous_state, current_state, signin_metrics::AccessPoint::kUnknown);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_SigningInFromUnsignedIn_DoesntCancelShare) {
  // Start a share flow.
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartShareOrManageFlow(
      std::move(mock_delegate), tab_groups::test::GenerateRandomTabGroupID(),
      CollaborationServiceShareOrManageEntryPoint::kUnknown);
  EXPECT_CALL(*delegate_ptr, Cancel(_)).Times(0);
  // Prepare a kSet event from unsigned in to signed in.
  PrimaryAccountChangeEvent::State previous_state;
  CoreAccountInfo account_info;
  account_info.gaia = kUserGaia;
  account_info.account_id = CoreAccountId::FromGaiaId(account_info.gaia);
  account_info.email = kConsumerUserEmail;
  PrimaryAccountChangeEvent::State current_state(account_info,
                                                 signin::ConsentLevel::kSignin);
  PrimaryAccountChangeEvent event_details(
      previous_state, current_state, signin_metrics::AccessPoint::kUnknown);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_SwitchingAccount_CancelsJoin) {
  // Start a join flow.
  GURL url = GURL(data_sharing::features::kDataSharingURL.Get() +
                  "?g=" + kGroupId + "&t=" + kAccessToken);
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartJoinFlow(std::move(mock_delegate), url);
  bool cancel_called = false;
  EXPECT_CALL(*delegate_ptr, Cancel(_))
      .WillOnce([&](CollaborationControllerDelegate::ResultCallback result) {
        cancel_called = true;
        std::move(result).Run(
            CollaborationControllerDelegate::Outcome::kSuccess);
        return true;
      });
  // Prepare a kSet event, switching accounts.
  CoreAccountInfo account_info_1;
  account_info_1.gaia = kUserGaia;
  account_info_1.account_id = CoreAccountId::FromGaiaId(account_info_1.gaia);
  account_info_1.email = kConsumerUserEmail;
  PrimaryAccountChangeEvent::State previous_state(
      account_info_1, signin::ConsentLevel::kSignin);
  CoreAccountInfo account_info_2;
  account_info_2.gaia = kOtherUserGaia;
  account_info_2.account_id = CoreAccountId::FromGaiaId(account_info_2.gaia);
  account_info_2.email = kOtherConsumerUserEmail;
  PrimaryAccountChangeEvent::State current_state(account_info_2,
                                                 signin::ConsentLevel::kSignin);
  PrimaryAccountChangeEvent event_details(
      previous_state, current_state, signin_metrics::AccessPoint::kUnknown);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);

  EXPECT_TRUE(cancel_called);
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_SwitchingAccount_CancelsShare) {
  // Start a share flow.
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartShareOrManageFlow(
      std::move(mock_delegate), tab_groups::test::GenerateRandomTabGroupID(),
      CollaborationServiceShareOrManageEntryPoint::kUnknown);
  bool cancel_called = false;
  EXPECT_CALL(*delegate_ptr, Cancel(_))
      .WillOnce([&](CollaborationControllerDelegate::ResultCallback result) {
        cancel_called = true;
        std::move(result).Run(
            CollaborationControllerDelegate::Outcome::kSuccess);
        return true;
      });
  // Prepare a kSet event, switching accounts.
  CoreAccountInfo account_info_1;
  account_info_1.gaia = kUserGaia;
  account_info_1.account_id = CoreAccountId::FromGaiaId(account_info_1.gaia);
  account_info_1.email = kConsumerUserEmail;
  PrimaryAccountChangeEvent::State previous_state(
      account_info_1, signin::ConsentLevel::kSignin);
  CoreAccountInfo account_info_2;
  account_info_2.gaia = kOtherUserGaia;
  account_info_2.account_id = CoreAccountId::FromGaiaId(account_info_2.gaia);
  account_info_2.email = kOtherConsumerUserEmail;
  PrimaryAccountChangeEvent::State current_state(account_info_2,
                                                 signin::ConsentLevel::kSignin);
  PrimaryAccountChangeEvent event_details(
      previous_state, current_state, signin_metrics::AccessPoint::kUnknown);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);

  EXPECT_TRUE(cancel_called);
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_Cleared_CancelsJoin) {
  // Start a join flow.
  GURL url = GURL(data_sharing::features::kDataSharingURL.Get() +
                  "?g=" + kGroupId + "&t=" + kAccessToken);
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartJoinFlow(std::move(mock_delegate), url);
  bool cancel_called = false;
  EXPECT_CALL(*delegate_ptr, Cancel(_))
      .WillOnce([&](CollaborationControllerDelegate::ResultCallback result) {
        cancel_called = true;
        std::move(result).Run(
            CollaborationControllerDelegate::Outcome::kSuccess);
        return true;
      });
  // Prepare a kCleared event.
  CoreAccountInfo account_info;
  account_info.gaia = kUserGaia;
  account_info.account_id = CoreAccountId::FromGaiaId(account_info.gaia);
  account_info.email = kConsumerUserEmail;
  PrimaryAccountChangeEvent::State previous_state(
      account_info, signin::ConsentLevel::kSignin);
  PrimaryAccountChangeEvent::State current_state;
  PrimaryAccountChangeEvent event_details(
      previous_state, current_state, signin_metrics::ProfileSignout::kTest);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);

  EXPECT_TRUE(cancel_called);
}

TEST_F(CollaborationServiceImplTest,
       OnPrimaryAccountChanged_Cleared_CancelsShare) {
  // Start a share flow.
  std::unique_ptr<MockCollaborationControllerDelegate> mock_delegate =
      std::make_unique<MockCollaborationControllerDelegate>();
  MockCollaborationControllerDelegate* delegate_ptr = mock_delegate.get();
  service_->StartShareOrManageFlow(
      std::move(mock_delegate), tab_groups::test::GenerateRandomTabGroupID(),
      CollaborationServiceShareOrManageEntryPoint::kUnknown);
  bool cancel_called = false;
  EXPECT_CALL(*delegate_ptr, Cancel(_))
      .WillOnce([&](CollaborationControllerDelegate::ResultCallback result) {
        cancel_called = true;
        std::move(result).Run(
            CollaborationControllerDelegate::Outcome::kSuccess);
        return true;
      });
  // Prepare a kCleared event.
  CoreAccountInfo account_info;
  account_info.gaia = kUserGaia;
  account_info.account_id = CoreAccountId::FromGaiaId(account_info.gaia);
  account_info.email = kConsumerUserEmail;
  PrimaryAccountChangeEvent::State previous_state(
      account_info, signin::ConsentLevel::kSignin);
  PrimaryAccountChangeEvent::State current_state;
  PrimaryAccountChangeEvent event_details(
      previous_state, current_state, signin_metrics::ProfileSignout::kTest);

  // Process the event.
  service_->OnPrimaryAccountChanged(event_details);

  EXPECT_TRUE(cancel_called);
}

TEST_F(CollaborationServiceImplTest,
       GetServiceStatus_VersionOutOfDateShowUpdateChromeUi) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      {data_sharing::features::kDataSharingFeature,
       data_sharing::features::kDataSharingEnableUpdateChromeUI,
       data_sharing::features::kSharedDataTypesKillSwitch},
      {data_sharing::features::kDataSharingJoinOnly});
  InitService();

  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kVersionOutOfDateShowUpdateChromeUi);
}

TEST_F(CollaborationServiceImplTest, GetServiceStatus_VersionOutOfDate) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      {
          data_sharing::features::kDataSharingJoinOnly,
          data_sharing::features::kSharedDataTypesKillSwitch,
      },
      {data_sharing::features::kDataSharingFeature,
       data_sharing::features::kDataSharingEnableUpdateChromeUI});
  InitService();

  EXPECT_EQ(service_->GetServiceStatus().collaboration_status,
            CollaborationStatus::kVersionOutOfDate);
}

}  // namespace collaboration