chromium/chrome/browser/password_manager/android/password_store_backend_migration_decorator_unittest.cc

// 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 "chrome/browser/password_manager/android/password_store_backend_migration_decorator.h"

#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/time.h"
#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_store/mock_password_store_backend.h"
#include "components/password_manager/core/browser/password_store/password_store.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/sync/test/test_sync_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace password_manager {
namespace {

using ::testing::_;
using ::testing::ElementsAreArray;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Ref;
using ::testing::Return;
using ::testing::VariantWith;
using ::testing::WithArg;
using ::testing::WithArgs;

PasswordForm CreateTestForm() {
  PasswordForm form;
  form.username_value = u"admin";
  form.password_value = u"admin";
  form.signon_realm = "https://admin.google.com/";
  form.url = GURL(form.signon_realm);
  return form;
}

}  // namespace

class PasswordStoreBackendMigrationDecoratorTest : public testing::Test {
 protected:
  void SetUp() override {
    prefs_.registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
                                          0);
    prefs_.registry()->RegisterBooleanPref(
        prefs::kUnenrolledFromGoogleMobileServicesDueToErrors, false);
    prefs_.registry()->RegisterIntegerPref(
        prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
    prefs_.registry()->RegisterIntegerPref(
        prefs::kPasswordsUseUPMLocalAndSeparateStores,
        static_cast<int>(
            password_manager::prefs::UseUpmLocalAndSeparateStoresState::
                kOffAndMigrationPending));

    auto built_in_backend =
        std::make_unique<NiceMock<MockPasswordStoreBackend>>();
    auto android_backend =
        std::make_unique<NiceMock<MockPasswordStoreBackend>>();
    built_in_backend_ = built_in_backend.get();
    android_backend_ = android_backend.get();
    backend_migration_decorator_ =
        std::make_unique<PasswordStoreBackendMigrationDecorator>(
            std::move(built_in_backend), std::move(android_backend), &prefs_);
    sync_service_.GetUserSettings()->SetSelectedTypes(
        /*sync_everything=*/false, /*types=*/{});
    backend_migration_decorator()->OnSyncServiceInitialized(&sync_service_);
  }

  void TearDown() override {
    EXPECT_CALL(android_backend(), Shutdown);
    EXPECT_CALL(built_in_backend(), Shutdown);
    built_in_backend_ = nullptr;
    android_backend_ = nullptr;
    backend_migration_decorator()->Shutdown(base::DoNothing());
  }

  PasswordStoreBackend* backend_migration_decorator() {
    return backend_migration_decorator_.get();
  }
  MockPasswordStoreBackend& built_in_backend() { return *built_in_backend_; }
  MockPasswordStoreBackend& android_backend() { return *android_backend_; }

  TestingPrefServiceSimple& prefs() { return prefs_; }

  void RunUntilIdle() { task_env_.RunUntilIdle(); }

  void FastForwardUntilNoTasksRemain() {
    task_env_.FastForwardUntilNoTasksRemain();
  }

  void FastForwardBy(base::TimeDelta delta) { task_env_.FastForwardBy(delta); }

  int GetPendingMainThreadTaskCount() {
    return task_env_.GetPendingMainThreadTaskCount();
  }

 private:
  base::test::SingleThreadTaskEnvironment task_env_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  raw_ptr<NiceMock<MockPasswordStoreBackend>> built_in_backend_;
  raw_ptr<NiceMock<MockPasswordStoreBackend>> android_backend_;
  TestingPrefServiceSimple prefs_;
  syncer::TestSyncService sync_service_;
  std::unique_ptr<PasswordStoreBackendMigrationDecorator>
      backend_migration_decorator_;
};

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       RecordsSchedulingOfLocalPwdMigration) {
  base::HistogramTester histogram_tester;
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(
          prefs::UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending));
  backend_migration_decorator()->InitBackend(
      /*affiliated_match_helper=*/nullptr,
      /*remote_form_changes_received=*/base::DoNothing(),
      /*sync_enabled_or_disabled_cb=*/base::DoNothing(),
      /*completion=*/base::DoNothing());
  // Migration should be scheduled.
  ASSERT_EQ(1, GetPendingMainThreadTaskCount());
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.UnifiedPasswordManager.MigrationForLocalUsers."
      "ProgressState",
      metrics_util::LocalPwdMigrationProgressState::kScheduled, 1);
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, GetAllLoginsAsync) {
  EXPECT_CALL(built_in_backend(), GetAllLoginsAsync);
  EXPECT_CALL(android_backend(), GetAllLoginsAsync).Times(0);

  backend_migration_decorator()->GetAllLoginsAsync(base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       GetAllLoginsAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  EXPECT_CALL(built_in_backend(), GetAllLoginsAsync).Times(0);
  EXPECT_CALL(android_backend(), GetAllLoginsAsync);

  backend_migration_decorator()->GetAllLoginsAsync(base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, IsAbleToSavePasswords) {
  EXPECT_CALL(built_in_backend(), IsAbleToSavePasswords).WillOnce(Return(true));
  EXPECT_CALL(android_backend(), IsAbleToSavePasswords).Times(0);

  EXPECT_TRUE(backend_migration_decorator()->IsAbleToSavePasswords());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       IsAbleToSavePasswordsAfterMigration) {
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  EXPECT_CALL(built_in_backend(), IsAbleToSavePasswords).Times(0);
  EXPECT_CALL(android_backend(), IsAbleToSavePasswords).WillOnce(Return(false));

  EXPECT_FALSE(backend_migration_decorator()->IsAbleToSavePasswords());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       GetAllLoginsWithAffiliationAndBrandingAsync) {
  EXPECT_CALL(built_in_backend(), GetAllLoginsWithAffiliationAndBrandingAsync);
  EXPECT_CALL(android_backend(), GetAllLoginsWithAffiliationAndBrandingAsync)
      .Times(0);

  backend_migration_decorator()->GetAllLoginsWithAffiliationAndBrandingAsync(
      base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       GetAllLoginsWithAffiliationAndBrandingAsyncAfterMigration) {
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  EXPECT_CALL(built_in_backend(), GetAllLoginsWithAffiliationAndBrandingAsync)
      .Times(0);
  EXPECT_CALL(android_backend(), GetAllLoginsWithAffiliationAndBrandingAsync);

  backend_migration_decorator()->GetAllLoginsWithAffiliationAndBrandingAsync(
      base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, GetAutofillableLoginsAsync) {
  EXPECT_CALL(built_in_backend(), GetAutofillableLoginsAsync);
  EXPECT_CALL(android_backend(), GetAutofillableLoginsAsync).Times(0);

  backend_migration_decorator()->GetAutofillableLoginsAsync(base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       GetAutofillableLoginsAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  EXPECT_CALL(built_in_backend(), GetAutofillableLoginsAsync).Times(0);
  EXPECT_CALL(android_backend(), GetAutofillableLoginsAsync);

  backend_migration_decorator()->GetAutofillableLoginsAsync(base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, FillMatchingLoginsAsync) {
  std::vector<PasswordFormDigest> forms = {
      PasswordFormDigest(PasswordForm::Scheme::kHtml, "https://google.com/",
                         GURL("https://google.com/"))};

  EXPECT_CALL(built_in_backend(),
              FillMatchingLoginsAsync(_, false, ElementsAreArray(forms)));
  EXPECT_CALL(android_backend(), FillMatchingLoginsAsync).Times(0);

  backend_migration_decorator()->FillMatchingLoginsAsync(
      base::DoNothing(), /*include_psl=*/false, forms);
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       FillMatchingLoginsAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  std::vector<PasswordFormDigest> forms = {
      PasswordFormDigest(PasswordForm::Scheme::kHtml, "https://google.com/",
                         GURL("https://google.com/"))};
  EXPECT_CALL(built_in_backend(), FillMatchingLoginsAsync).Times(0);
  EXPECT_CALL(android_backend(),
              FillMatchingLoginsAsync(_, false, ElementsAreArray(forms)));

  backend_migration_decorator()->FillMatchingLoginsAsync(
      base::DoNothing(), /*include_psl=*/false, forms);
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       GetGroupedMatchingLoginsAsync) {
  PasswordFormDigest form_digest(PasswordForm::Scheme::kHtml,
                                 "https://google.com/",
                                 GURL("https://google.com/"));
  EXPECT_CALL(built_in_backend(),
              GetGroupedMatchingLoginsAsync(Ref(form_digest), _));
  EXPECT_CALL(android_backend(), GetGroupedMatchingLoginsAsync).Times(0);

  backend_migration_decorator()->GetGroupedMatchingLoginsAsync(
      form_digest, base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       GetGroupedMatchingLoginsAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  PasswordFormDigest form_digest(PasswordForm::Scheme::kHtml,
                                 "https://google.com/",
                                 GURL("https://google.com/"));
  EXPECT_CALL(built_in_backend(), GetGroupedMatchingLoginsAsync).Times(0);
  EXPECT_CALL(android_backend(),
              GetGroupedMatchingLoginsAsync(Ref(form_digest), _));

  backend_migration_decorator()->GetGroupedMatchingLoginsAsync(
      form_digest, base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, AddLoginAsync) {
  EXPECT_CALL(built_in_backend(), AddLoginAsync(CreateTestForm(), _));
  EXPECT_CALL(android_backend(), AddLoginAsync).Times(0);

  backend_migration_decorator()->AddLoginAsync(CreateTestForm(),
                                               base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       AddLoginAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  EXPECT_CALL(built_in_backend(), AddLoginAsync).Times(0);
  EXPECT_CALL(android_backend(), AddLoginAsync(CreateTestForm(), _));

  backend_migration_decorator()->AddLoginAsync(CreateTestForm(),
                                               base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, UpdateLoginAsync) {
  EXPECT_CALL(built_in_backend(), UpdateLoginAsync(CreateTestForm(), _));
  EXPECT_CALL(android_backend(), UpdateLoginAsync).Times(0);

  backend_migration_decorator()->UpdateLoginAsync(CreateTestForm(),
                                                  base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       UpdateLoginAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  EXPECT_CALL(built_in_backend(), UpdateLoginAsync).Times(0);
  EXPECT_CALL(android_backend(), UpdateLoginAsync(CreateTestForm(), _));

  backend_migration_decorator()->UpdateLoginAsync(CreateTestForm(),
                                                  base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, RemoveLoginAsync) {
  EXPECT_CALL(built_in_backend(), RemoveLoginAsync(_, CreateTestForm(), _));
  EXPECT_CALL(android_backend(), RemoveLoginAsync).Times(0);

  backend_migration_decorator()->RemoveLoginAsync(FROM_HERE, CreateTestForm(),
                                                  base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       RemoveLoginAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  EXPECT_CALL(built_in_backend(), RemoveLoginAsync(_, CreateTestForm(), _));
  EXPECT_CALL(android_backend(), RemoveLoginAsync(_, CreateTestForm(), _));

  backend_migration_decorator()->RemoveLoginAsync(FROM_HERE, CreateTestForm(),
                                                  base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       RemoveLoginsByURLAndTimeAsync) {
  base::RepeatingCallback<bool(const GURL&)> url_filter =
      base::BindRepeating([](const GURL& url) { return true; });
  base::Time delete_begin = base::Time::FromTimeT(1000);
  base::Time delete_end = base::Time::FromTimeT(2000);

  EXPECT_CALL(built_in_backend(),
              RemoveLoginsByURLAndTimeAsync(_, url_filter, delete_begin,
                                            delete_end, _, _));
  EXPECT_CALL(android_backend(), RemoveLoginsByURLAndTimeAsync).Times(0);

  backend_migration_decorator()->RemoveLoginsByURLAndTimeAsync(
      FROM_HERE, url_filter, delete_begin, delete_end,
      base::OnceCallback<void(bool)>(), base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       RemoveLoginsByURLAndTimeAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  base::RepeatingCallback<bool(const GURL&)> url_filter =
      base::BindRepeating([](const GURL& url) { return true; });
  base::Time delete_begin = base::Time::FromTimeT(1000);
  base::Time delete_end = base::Time::FromTimeT(2000);
  EXPECT_CALL(built_in_backend(),
              RemoveLoginsByURLAndTimeAsync(_, url_filter, delete_begin,
                                            delete_end, _, _));
  EXPECT_CALL(android_backend(),
              RemoveLoginsByURLAndTimeAsync(_, url_filter, delete_begin,
                                            delete_end, _, _));

  backend_migration_decorator()->RemoveLoginsByURLAndTimeAsync(
      FROM_HERE, url_filter, delete_begin, delete_end,
      base::OnceCallback<void(bool)>(), base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       RemoveLoginsCreatedBetweenAsync) {
  base::Time delete_begin = base::Time::FromTimeT(1000);
  base::Time delete_end = base::Time::FromTimeT(2000);

  EXPECT_CALL(built_in_backend(),
              RemoveLoginsCreatedBetweenAsync(_, delete_begin, delete_end, _));
  EXPECT_CALL(android_backend(), RemoveLoginsCreatedBetweenAsync).Times(0);

  backend_migration_decorator()->RemoveLoginsCreatedBetweenAsync(
      FROM_HERE, delete_begin, delete_end, base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       RemoveLoginsCreatedBetweenAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  base::Time delete_begin = base::Time::FromTimeT(1000);
  base::Time delete_end = base::Time::FromTimeT(2000);
  EXPECT_CALL(built_in_backend(),
              RemoveLoginsCreatedBetweenAsync(_, delete_begin, delete_end, _));
  EXPECT_CALL(android_backend(),
              RemoveLoginsCreatedBetweenAsync(_, delete_begin, delete_end, _));

  backend_migration_decorator()->RemoveLoginsCreatedBetweenAsync(
      FROM_HERE, delete_begin, delete_end, base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       DisableAutoSignInForOriginsAsync) {
  base::RepeatingCallback<bool(const GURL&)> url_filter =
      base::BindRepeating([](const GURL& url) { return true; });

  EXPECT_CALL(built_in_backend(),
              DisableAutoSignInForOriginsAsync(url_filter, _));
  EXPECT_CALL(android_backend(), DisableAutoSignInForOriginsAsync).Times(0);

  backend_migration_decorator()->DisableAutoSignInForOriginsAsync(
      url_filter, base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       DisableAutoSignInForOriginsAsyncAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));

  base::RepeatingCallback<bool(const GURL&)> url_filter =
      base::BindRepeating([](const GURL& url) { return true; });
  EXPECT_CALL(built_in_backend(), DisableAutoSignInForOriginsAsync).Times(0);
  EXPECT_CALL(android_backend(),
              DisableAutoSignInForOriginsAsync(url_filter, _));

  backend_migration_decorator()->DisableAutoSignInForOriginsAsync(
      url_filter, base::DoNothing());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       DisableSavingDuringLocalPasswordsMigration) {
  backend_migration_decorator()->InitBackend(
      /*affiliated_match_helper=*/nullptr,
      /*remote_form_changes_received=*/base::DoNothing(),
      /*sync_enabled_or_disabled_cb=*/base::DoNothing(),
      /*completion=*/base::DoNothing());

  // True so far because the migration is deferred.
  EXPECT_CALL(built_in_backend(), IsAbleToSavePasswords)
      .WillRepeatedly(Return(true));
  ASSERT_TRUE(backend_migration_decorator()->IsAbleToSavePasswords());

  FastForwardUntilNoTasksRemain();

  // False now because the migration is ongoing.
  EXPECT_FALSE(backend_migration_decorator()->IsAbleToSavePasswords());
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest, RemoteFormChangesReceived) {
  base::MockCallback<PasswordStoreBackend::RemoteChangesReceived>
      original_callback;

  // Both backends receive a callback that they trigger for new remote changes.
  PasswordStoreBackend::RemoteChangesReceived built_in_remote_changes_callback;
  EXPECT_CALL(built_in_backend(), InitBackend)
      .WillOnce(testing::SaveArg<1>(&built_in_remote_changes_callback));
  PasswordStoreBackend::RemoteChangesReceived android_remote_changes_callback;
  EXPECT_CALL(android_backend(), InitBackend)
      .WillOnce(testing::SaveArg<1>(&android_remote_changes_callback));
  backend_migration_decorator()->InitBackend(
      nullptr, original_callback.Get(), base::DoNothing(), base::DoNothing());

  EXPECT_CALL(original_callback, Run).Times(0);
  android_remote_changes_callback.Run(std::nullopt);
  testing::Mock::VerifyAndClearExpectations(&original_callback);

  EXPECT_CALL(original_callback, Run);
  built_in_remote_changes_callback.Run(std::nullopt);
  testing::Mock::VerifyAndClearExpectations(&original_callback);
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       RemoteFormChangesReceivedAfterMigration) {
  // Indicate completeness of local password migration.
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(prefs::UseUpmLocalAndSeparateStoresState::kOn));
  base::MockCallback<PasswordStoreBackend::RemoteChangesReceived>
      original_callback;

  PasswordStoreBackend::RemoteChangesReceived built_in_remote_changes_callback;
  EXPECT_CALL(built_in_backend(), InitBackend)
      .WillOnce(testing::SaveArg<1>(&built_in_remote_changes_callback));
  PasswordStoreBackend::RemoteChangesReceived android_remote_changes_callback;
  EXPECT_CALL(android_backend(), InitBackend)
      .WillOnce(testing::SaveArg<1>(&android_remote_changes_callback));
  backend_migration_decorator()->InitBackend(
      nullptr, original_callback.Get(), base::DoNothing(), base::DoNothing());

  EXPECT_CALL(original_callback, Run);
  android_remote_changes_callback.Run(std::nullopt);
  testing::Mock::VerifyAndClearExpectations(&original_callback);

  EXPECT_CALL(original_callback, Run).Times(0);
  built_in_remote_changes_callback.Run(std::nullopt);
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       CallCompletionCallbackAfterInit) {
  base::MockCallback<base::OnceCallback<void(bool)>> completion_callback;

  // Both backends need to be invoked for a successful completion call.
  EXPECT_CALL(built_in_backend(), InitBackend)
      .WillOnce(WithArg<3>(
          testing::Invoke([](base::OnceCallback<void(bool)> reply) -> void {
            std::move(reply).Run(true);
          })));

  base::OnceCallback<void(bool)> captured_android_backend_reply;
  EXPECT_CALL(android_backend(), InitBackend)
      .WillOnce(WithArg<3>(
          testing::Invoke([&](base::OnceCallback<void(bool)> reply) -> void {
            captured_android_backend_reply = std::move(reply);
          })));

  backend_migration_decorator()->InitBackend(
      nullptr, base::DoNothing(), base::DoNothing(), completion_callback.Get());

  EXPECT_CALL(completion_callback, Run(true));
  std::move(captured_android_backend_reply).Run(true);
}

TEST_F(PasswordStoreBackendMigrationDecoratorTest,
       MigrationIsStartedWithDelayAfterInit) {
  prefs().SetInteger(
      prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(
          prefs::UseUpmLocalAndSeparateStoresState::kOffAndMigrationPending));

  backend_migration_decorator()->InitBackend(
      nullptr, /* remote_form_changes_received= */ base::DoNothing(),
      /* sync_enabled_or_disabled_cb= */ base::DoNothing(),
      /* completion= */ base::DoNothing());
  // Migration should be scheduled.
  EXPECT_EQ(1, GetPendingMainThreadTaskCount());

  FastForwardBy(kLocalPasswordsMigrationToAndroidBackendDelay);
  // Migration should be started by now.
  EXPECT_EQ(0, GetPendingMainThreadTaskCount());
}

}  // namespace password_manager