blob: 243a3d32468123d3ab29e2fa72a7c1f03e93a44d [file] [log] [blame]
// Copyright (c) 2012 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 <stdint.h>
#include <limits>
#include <tuple>
#include "base/guid.h"
#include "base/hash.h"
#include "base/macros.h"
#include "base/rand_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/sync/test/integration/passwords_helper.h"
#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/engine/cycle/sync_cycle_snapshot.h"
#include "components/sync/engine/model_safe_worker.h"
using passwords_helper::AddLogin;
using passwords_helper::AllProfilesContainSamePasswordForms;
using passwords_helper::AllProfilesContainSamePasswordFormsAsVerifier;
using passwords_helper::CreateTestPasswordForm;
using passwords_helper::GetPasswordCount;
using passwords_helper::GetPasswordStore;
using passwords_helper::GetVerifierPasswordCount;
using passwords_helper::GetVerifierPasswordStore;
using passwords_helper::RemoveLogin;
using passwords_helper::RemoveLogins;
using passwords_helper::UpdateLogin;
using autofill::PasswordForm;
static const char* kValidPassphrase = "passphrase!";
class TwoClientPasswordsSyncTest
: public testing::WithParamInterface<std::tuple<bool, bool>>,
public SyncTest {
public:
TwoClientPasswordsSyncTest() : SyncTest(TWO_CLIENT) {}
~TwoClientPasswordsSyncTest() override {}
bool TestUsesSelfNotifications() override { return false; }
protected:
void BeforeSetupClient(int index) override {
const bool should_enable_pseudo_uss =
index == 0 ? std::get<0>(GetParam()) : std::get<1>(GetParam());
// The value of the feature kSyncPseudoUSSPasswords only matters during the
// setup of each client, when the profile is created, ProfileSyncService
// instantiated as well as the datatype controllers. By overriding the
// feature, we can influence whether client |index| is running with the new
// codepath or the legacy one.
override_features_ = std::make_unique<base::test::ScopedFeatureList>();
if (should_enable_pseudo_uss) {
override_features_->InitAndEnableFeature(
switches::kSyncPseudoUSSPasswords);
} else {
override_features_->InitAndDisableFeature(
switches::kSyncPseudoUSSPasswords);
}
}
private:
std::unique_ptr<base::test::ScopedFeatureList> override_features_;
DISALLOW_COPY_AND_ASSIGN(TwoClientPasswordsSyncTest);
};
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_Add DISABLED_Add
#else
#define MAYBE_Add Add
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest, E2E_ENABLED(MAYBE_Add)) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
PasswordForm form = CreateTestPasswordForm(0);
AddLogin(GetPasswordStore(0), form);
ASSERT_EQ(1, GetPasswordCount(0));
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
ASSERT_EQ(1, GetPasswordCount(1));
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_Race DISABLED_Race
#else
#define MAYBE_Race Race
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest, E2E_ENABLED(MAYBE_Race)) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(AllProfilesContainSamePasswordForms());
PasswordForm form0 = CreateTestPasswordForm(0);
AddLogin(GetPasswordStore(0), form0);
PasswordForm form1 = form0;
form1.password_value = base::ASCIIToUTF16("new_password");
AddLogin(GetPasswordStore(1), form1);
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_SetPassphraseAndAddPassword DISABLED_SetPassphraseAndAddPassword
#else
#define MAYBE_SetPassphraseAndAddPassword SetPassphraseAndAddPassword
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest,
E2E_ENABLED(MAYBE_SetPassphraseAndAddPassword)) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
GetSyncService(0)->SetEncryptionPassphrase(kValidPassphrase);
ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(0)).Wait());
ASSERT_TRUE(PassphraseRequiredChecker(GetSyncService(1)).Wait());
ASSERT_TRUE(GetSyncService(1)->SetDecryptionPassphrase(kValidPassphrase));
ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(1)).Wait());
PasswordForm form = CreateTestPasswordForm(0);
AddLogin(GetPasswordStore(0), form);
ASSERT_EQ(1, GetPasswordCount(0));
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_Update DISABLED_Update
#else
#define MAYBE_Update Update
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest, MAYBE_Update) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
PasswordForm form = CreateTestPasswordForm(0);
AddLogin(GetVerifierPasswordStore(), form);
AddLogin(GetPasswordStore(0), form);
// Wait for client 0 to commit and client 1 to receive the update.
ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
form.password_value = base::ASCIIToUTF16("new_password");
UpdateLogin(GetVerifierPasswordStore(), form);
UpdateLogin(GetPasswordStore(1), form);
ASSERT_EQ(1, GetVerifierPasswordCount());
// Wait for client 1 to commit and client 0 to receive the update.
ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(0).Wait());
ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_Delete DISABLED_Delete
#else
#define MAYBE_Delete Delete
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest, MAYBE_Delete) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
PasswordForm form0 = CreateTestPasswordForm(0);
AddLogin(GetVerifierPasswordStore(), form0);
AddLogin(GetPasswordStore(0), form0);
PasswordForm form1 = CreateTestPasswordForm(1);
AddLogin(GetVerifierPasswordStore(), form1);
AddLogin(GetPasswordStore(0), form1);
// Wait for client 0 to commit and client 1 to receive the update.
ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
RemoveLogin(GetPasswordStore(1), form0);
RemoveLogin(GetVerifierPasswordStore(), form0);
ASSERT_EQ(1, GetVerifierPasswordCount());
// Wait for deletion from client 1 to propagate.
ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(0).Wait());
ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
}
// https://crbug.com/874929, flaky on all platform.
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest,
DISABLED_SetPassphraseAndThenSetupSync) {
ASSERT_TRUE(SetupClients());
ASSERT_TRUE(GetClient(0)->SetupSync());
GetSyncService(0)->SetEncryptionPassphrase(kValidPassphrase);
ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(0)).Wait());
// When client 1 hits a passphrase required state, we can infer that
// client 0's passphrase has been committed. to the server.
ASSERT_FALSE(GetClient(1)->SetupSync());
ASSERT_TRUE(PassphraseRequiredChecker(GetSyncService(1)).Wait());
// Get client 1 out of the passphrase required state.
ASSERT_TRUE(GetSyncService(1)->SetDecryptionPassphrase(kValidPassphrase));
ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(1)).Wait());
// We must mark the setup complete now, since we just entered the passphrase
// and the previous SetupSync() call failed.
GetClient(1)->FinishSyncSetup();
// Move around some passwords to make sure it's all working.
PasswordForm form0 = CreateTestPasswordForm(0);
AddLogin(GetPasswordStore(0), form0);
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_DeleteTwo DISABLED_DeleteTwo
#else
#define MAYBE_DeleteTwo DeleteTwo
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest, E2E_ONLY(MAYBE_DeleteTwo)) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(AllProfilesContainSamePasswordForms());
PasswordForm form0 = CreateTestPasswordForm(base::Hash(base::GenerateGUID()));
PasswordForm form1 = CreateTestPasswordForm(base::Hash(base::GenerateGUID()));
AddLogin(GetPasswordStore(0), form0);
AddLogin(GetPasswordStore(0), form1);
const int init_password_count = GetPasswordCount(0);
// Wait for client 0 to commit and client 1 to receive the update.
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
ASSERT_EQ(init_password_count, GetPasswordCount(1));
RemoveLogin(GetPasswordStore(1), form0);
// Wait for deletion from client 1 to propagate.
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
ASSERT_EQ(init_password_count - 1, GetPasswordCount(0));
RemoveLogin(GetPasswordStore(1), form1);
// Wait for deletion from client 1 to propagate.
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
ASSERT_EQ(init_password_count - 2, GetPasswordCount(0));
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_DeleteAll DISABLED_DeleteAll
#else
#define MAYBE_DeleteAll DeleteAll
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest, MAYBE_DeleteAll) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
PasswordForm form0 = CreateTestPasswordForm(0);
AddLogin(GetVerifierPasswordStore(), form0);
AddLogin(GetPasswordStore(0), form0);
PasswordForm form1 = CreateTestPasswordForm(1);
AddLogin(GetVerifierPasswordStore(), form1);
AddLogin(GetPasswordStore(0), form1);
ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
RemoveLogins(GetPasswordStore(1));
RemoveLogins(GetVerifierPasswordStore());
ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(0).Wait());
ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
ASSERT_EQ(0, GetVerifierPasswordCount());
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_Merge DISABLED_Merge
#else
#define MAYBE_Merge Merge
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest, E2E_ENABLED(MAYBE_Merge)) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
ASSERT_TRUE(AllProfilesContainSamePasswordForms());
PasswordForm form0 = CreateTestPasswordForm(0);
AddLogin(GetPasswordStore(0), form0);
PasswordForm form1 = CreateTestPasswordForm(1);
AddLogin(GetPasswordStore(1), form1);
PasswordForm form2 = CreateTestPasswordForm(2);
AddLogin(GetPasswordStore(1), form2);
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
ASSERT_EQ(3, GetPasswordCount(0));
}
// Flaky on TSAN: crbug.com/915219
#if defined(THREAD_SANITIZER)
#define MAYBE_TwoClientAddPass DISABLED_TwoClientAddPass
#else
#define MAYBE_TwoClientAddPass TwoClientAddPass
#endif
IN_PROC_BROWSER_TEST_P(TwoClientPasswordsSyncTest,
E2E_ONLY(MAYBE_TwoClientAddPass)) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// All profiles should sync same passwords.
ASSERT_TRUE(SamePasswordFormsChecker().Wait())
<< "Initial password forms did not match for all profiles";
const int init_password_count = GetPasswordCount(0);
// Add one new password per profile. A unique form is created for each to
// prevent them from overwriting each other.
for (int i = 0; i < num_clients(); ++i) {
AddLogin(GetPasswordStore(i), CreateTestPasswordForm(base::RandInt(
0, std::numeric_limits<int32_t>::max())));
}
// Blocks and waits for password forms in all profiles to match.
ASSERT_TRUE(SamePasswordFormsChecker().Wait());
// Check that total number of passwords is as expected.
for (int i = 0; i < num_clients(); ++i) {
ASSERT_EQ(GetPasswordCount(i), init_password_count + num_clients()) <<
"Total password count is wrong.";
}
}
// We instantiate every test 4 times, for every combination of pseudo-USS being
// enabled in individual clients. This verifies backward-compatibility between
// the two implementations.
INSTANTIATE_TEST_CASE_P(USS,
TwoClientPasswordsSyncTest,
::testing::Combine(::testing::Values(false, true),
::testing::Values(false, true)));