blob: 3fd52dc0b5f7b7b1e6bc965da5346f0cc1a08282 [file] [log] [blame]
// Copyright 2013 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 "base/bind.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/sync/test/integration/bookmarks_helper.h"
#include "chrome/browser/sync/test/integration/retry_verifier.h"
#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
#include "components/sync/driver/profile_sync_service.h"
#include "components/sync/test/fake_server/fake_server_http_post_provider.h"
#include "content/public/test/network_connection_change_simulator.h"
#include "net/base/network_change_notifier.h"
namespace {
using bookmarks_helper::AddFolder;
using bookmarks_helper::ModelMatchesVerifier;
using syncer::SyncCycleSnapshot;
class SyncExponentialBackoffTest : public SyncTest {
public:
SyncExponentialBackoffTest() : SyncTest(SINGLE_CLIENT) {}
~SyncExponentialBackoffTest() override {}
void SetUp() override {
// This is needed to avoid spurious notifications initiated by the platform.
net::NetworkChangeNotifier::SetTestNotificationsOnly(true);
SyncTest::SetUp();
}
private:
DISALLOW_COPY_AND_ASSIGN(SyncExponentialBackoffTest);
};
// Helper class that checks if a sync client has successfully gone through
// exponential backoff after it encounters an error.
class ExponentialBackoffChecker : public SingleClientStatusChangeChecker {
public:
explicit ExponentialBackoffChecker(syncer::ProfileSyncService* pss)
: SingleClientStatusChangeChecker(pss) {
const SyncCycleSnapshot& snap =
service()->GetLastCycleSnapshotForDebugging();
retry_verifier_.Initialize(snap);
}
// Checks if backoff is complete. Called repeatedly each time PSS notifies
// observers of a state change.
bool IsExitConditionSatisfied() override {
const SyncCycleSnapshot& snap =
service()->GetLastCycleSnapshotForDebugging();
retry_verifier_.VerifyRetryInterval(snap);
return (retry_verifier_.done() && retry_verifier_.Succeeded());
}
std::string GetDebugMessage() const override {
return base::StringPrintf("Verifying backoff intervals (%d/%d)",
retry_verifier_.retry_count(),
RetryVerifier::kMaxRetry);
}
private:
// Keeps track of the number of attempts at exponential backoff and its
// related bookkeeping information for verification.
RetryVerifier retry_verifier_;
DISALLOW_COPY_AND_ASSIGN(ExponentialBackoffChecker);
};
IN_PROC_BROWSER_TEST_F(SyncExponentialBackoffTest, OfflineToOnline) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Add an item and ensure that sync is successful.
ASSERT_TRUE(AddFolder(0, 0, "folder1"));
ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
fake_server::FakeServerHttpPostProvider::DisableNetwork();
// Add a new item to trigger another sync cycle.
ASSERT_TRUE(AddFolder(0, 0, "folder2"));
// Verify that the client goes into exponential backoff while it is unable to
// reach the sync server.
ASSERT_TRUE(ExponentialBackoffChecker(GetSyncService(0)).Wait());
// Trigger network change notification and remember time when it happened.
// Ensure that scheduler runs canary job immediately.
fake_server::FakeServerHttpPostProvider::EnableNetwork();
content::NetworkConnectionChangeSimulator connection_change_simulator;
connection_change_simulator.SetConnectionType(
network::mojom::ConnectionType::CONNECTION_ETHERNET);
base::Time network_notification_time = base::Time::Now();
// Verify that sync was able to recover.
ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
ASSERT_TRUE(ModelMatchesVerifier(0));
// Verify that recovery time is short. Without canary job recovery time would
// be more than 5 seconds.
base::TimeDelta recovery_time =
GetSyncService(0)->GetLastCycleSnapshotForDebugging().sync_start_time() -
network_notification_time;
ASSERT_LE(recovery_time, base::TimeDelta::FromSeconds(2));
}
IN_PROC_BROWSER_TEST_F(SyncExponentialBackoffTest, ServerRedirect) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Add an item and ensure that sync is successful.
ASSERT_TRUE(AddFolder(0, 0, "folder1"));
ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
GetFakeServer()->SetHttpError(net::HTTP_USE_PROXY);
// Add a new item to trigger another sync cycle.
ASSERT_TRUE(AddFolder(0, 0, "folder2"));
// Verify that the client goes into exponential backoff while it is unable to
// reach the sync server.
ASSERT_TRUE(ExponentialBackoffChecker(GetSyncService(0)).Wait());
}
IN_PROC_BROWSER_TEST_F(SyncExponentialBackoffTest, InternalServerError) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Add an item and ensure that sync is successful.
ASSERT_TRUE(AddFolder(0, 0, "folder1"));
ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
GetFakeServer()->SetHttpError(net::HTTP_INTERNAL_SERVER_ERROR);
// Add a new item to trigger another sync cycle.
ASSERT_TRUE(AddFolder(0, 0, "folder2"));
// Verify that the client goes into exponential backoff while it is unable to
// reach the sync server.
ASSERT_TRUE(ExponentialBackoffChecker(GetSyncService(0)).Wait());
}
IN_PROC_BROWSER_TEST_F(SyncExponentialBackoffTest, TransientErrorTest) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
// Add an item and ensure that sync is successful.
ASSERT_TRUE(AddFolder(0, 0, "folder1"));
ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
GetFakeServer()->TriggerError(sync_pb::SyncEnums::TRANSIENT_ERROR);
// Add a new item to trigger another sync cycle.
ASSERT_TRUE(AddFolder(0, 0, "folder2"));
// Verify that the client goes into exponential backoff while it is unable to
// reach the sync server.
ASSERT_TRUE(ExponentialBackoffChecker(GetSyncService(0)).Wait());
}
} // namespace