blob: ebaed51032d292a789aca1ce4d726f1966259adc [file] [log] [blame]
// Copyright 2015 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 "chrome/browser/background_sync/background_sync_controller_impl.h"
#include <stdint.h>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "chrome/browser/engagement/site_engagement_score.h"
#include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/test/base/testing_profile.h"
#include "components/history/core/browser/history_database_params.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/test/test_history_database.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/background_sync_parameters.h"
#include "content/public/browser/background_sync_registration.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/background_sync/background_sync.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
#if defined(OS_ANDROID)
#include "chrome/browser/android/background_sync_launcher_android.h"
#endif
namespace {
using content::BackgroundSyncController;
const char kFieldTrialGroup[] = "GroupA";
const char kExampleUrl[] = "https://www.example.com/foo/";
const char kTag[] = "test_tag";
constexpr base::TimeDelta kSmallerThanMinGap = base::TimeDelta::FromHours(11);
constexpr base::TimeDelta kLargerThanMinGap = base::TimeDelta::FromHours(13);
constexpr base::TimeDelta kLargerThanMinGapExpectedDelay =
base::TimeDelta::FromHours(24);
std::unique_ptr<KeyedService> BuildTestHistoryService(
const base::FilePath& file_path,
content::BrowserContext* context) {
auto service = std::make_unique<history::HistoryService>();
service->Init(history::TestHistoryDatabaseParamsForPath(file_path));
return service;
}
class BackgroundSyncControllerImplTest : public testing::Test {
protected:
BackgroundSyncControllerImplTest()
: task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {
ResetFieldTrialList();
#if defined(OS_ANDROID)
BackgroundSyncLauncherAndroid::SetPlayServicesVersionCheckDisabledForTests(
true);
#endif
}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath sub_dir =
temp_dir_.GetPath().AppendASCII("BackgroundSyncTest");
ASSERT_TRUE(base::CreateDirectory(sub_dir));
HistoryServiceFactory::GetInstance()->SetTestingFactory(
&profile_, base::BindRepeating(&BuildTestHistoryService, sub_dir));
controller_ = std::make_unique<BackgroundSyncControllerImpl>(&profile_);
}
void ResetFieldTrialList() {
variations::testing::ClearAllVariationParams();
base::FieldTrialList::CreateFieldTrial(
BackgroundSyncControllerImpl::kFieldTrialName, kFieldTrialGroup);
}
content::BackgroundSyncRegistration MakeBackgroundSyncRegistration(
int min_interval,
int num_attempts,
blink::mojom::BackgroundSyncType sync_type) {
url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
content::BackgroundSyncRegistration registration;
registration.set_origin(origin);
blink::mojom::SyncRegistrationOptions options(kTag, min_interval);
*registration.options() = std::move(options);
registration.set_num_attempts(num_attempts);
return registration;
}
base::ScopedTempDir temp_dir_;
content::BrowserTaskEnvironment task_environment_;
TestingProfile profile_;
std::unique_ptr<BackgroundSyncControllerImpl> controller_;
DISALLOW_COPY_AND_ASSIGN(BackgroundSyncControllerImplTest);
};
TEST_F(BackgroundSyncControllerImplTest, NoFieldTrial) {
content::BackgroundSyncParameters original;
content::BackgroundSyncParameters overrides;
controller_->GetParameterOverrides(&overrides);
EXPECT_EQ(original, overrides);
}
TEST_F(BackgroundSyncControllerImplTest, SomeParamsSet) {
std::map<std::string, std::string> field_parameters;
field_parameters[BackgroundSyncControllerImpl::kDisabledParameterName] =
"TrUe";
field_parameters[BackgroundSyncControllerImpl::kInitialRetryParameterName] =
"100";
ASSERT_TRUE(variations::AssociateVariationParams(
BackgroundSyncControllerImpl::kFieldTrialName, kFieldTrialGroup,
field_parameters));
content::BackgroundSyncParameters original;
content::BackgroundSyncParameters sync_parameters;
controller_->GetParameterOverrides(&sync_parameters);
EXPECT_TRUE(sync_parameters.disable);
EXPECT_EQ(base::TimeDelta::FromSeconds(100),
sync_parameters.initial_retry_delay);
EXPECT_EQ(original.max_sync_attempts, sync_parameters.max_sync_attempts);
EXPECT_EQ(original.retry_delay_factor, sync_parameters.retry_delay_factor);
EXPECT_EQ(original.min_sync_recovery_time,
sync_parameters.min_sync_recovery_time);
EXPECT_EQ(original.max_sync_event_duration,
sync_parameters.max_sync_event_duration);
EXPECT_EQ(original.min_periodic_sync_events_interval,
sync_parameters.min_periodic_sync_events_interval);
}
TEST_F(BackgroundSyncControllerImplTest, AllParamsSet) {
std::map<std::string, std::string> field_parameters;
field_parameters[BackgroundSyncControllerImpl::kDisabledParameterName] =
"FALSE";
field_parameters[BackgroundSyncControllerImpl::kInitialRetryParameterName] =
"100";
field_parameters[BackgroundSyncControllerImpl::kMaxAttemptsParameterName] =
"200";
field_parameters[BackgroundSyncControllerImpl::
kMaxAttemptsWithNotificationPermissionParameterName] =
"250";
field_parameters
[BackgroundSyncControllerImpl::kRetryDelayFactorParameterName] = "300";
field_parameters[BackgroundSyncControllerImpl::kMinSyncRecoveryTimeName] =
"400";
field_parameters[BackgroundSyncControllerImpl::kMaxSyncEventDurationName] =
"500";
field_parameters
[BackgroundSyncControllerImpl::kMinPeriodicSyncEventsInterval] = "43200";
ASSERT_TRUE(variations::AssociateVariationParams(
BackgroundSyncControllerImpl::kFieldTrialName, kFieldTrialGroup,
field_parameters));
content::BackgroundSyncParameters sync_parameters;
controller_->GetParameterOverrides(&sync_parameters);
EXPECT_FALSE(sync_parameters.disable);
EXPECT_EQ(base::TimeDelta::FromSeconds(100),
sync_parameters.initial_retry_delay);
EXPECT_EQ(200, sync_parameters.max_sync_attempts);
EXPECT_EQ(250,
sync_parameters.max_sync_attempts_with_notification_permission);
EXPECT_EQ(300, sync_parameters.retry_delay_factor);
EXPECT_EQ(base::TimeDelta::FromSeconds(400),
sync_parameters.min_sync_recovery_time);
EXPECT_EQ(base::TimeDelta::FromSeconds(500),
sync_parameters.max_sync_event_duration);
EXPECT_EQ(base::TimeDelta::FromSeconds(43200),
sync_parameters.min_periodic_sync_events_interval);
}
TEST_F(BackgroundSyncControllerImplTest, OneShotSyncMultipleAttempts) {
controller_ = std::make_unique<BackgroundSyncControllerImpl>(
profile_.GetOffTheRecordProfile());
content::BackgroundSyncParameters sync_parameters;
url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
SiteEngagementScore::SetParamValuesForTesting();
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(
GURL(kExampleUrl), SiteEngagementScore::GetHighEngagementBoundary());
base::TimeDelta delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ -1,
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::ONE_SHOT),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay, base::TimeDelta());
base::TimeDelta delay_after_attempt1 = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ -1,
/* num_attempts= */ 1, blink::mojom::BackgroundSyncType::ONE_SHOT),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay_after_attempt1, sync_parameters.initial_retry_delay);
base::TimeDelta delay_after_attempt2 = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ -1,
/* num_attempts= */ 2, blink::mojom::BackgroundSyncType::ONE_SHOT),
&sync_parameters, base::TimeDelta::Max());
EXPECT_LT(delay_after_attempt1, delay_after_attempt2);
}
TEST_F(BackgroundSyncControllerImplTest, PeriodicSyncMultipleAttempts) {
controller_ = std::make_unique<BackgroundSyncControllerImpl>(
profile_.GetOffTheRecordProfile());
content::BackgroundSyncParameters sync_parameters;
url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
SiteEngagementScore::SetParamValuesForTesting();
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(
GURL(kExampleUrl), SiteEngagementScore::GetHighEngagementBoundary());
base::TimeDelta delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay, sync_parameters.min_periodic_sync_events_interval);
base::TimeDelta delay_after_attempt1 = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 1, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay_after_attempt1, sync_parameters.initial_retry_delay);
base::TimeDelta delay_after_attempt2 = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 2, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_LT(delay_after_attempt1, delay_after_attempt2);
}
TEST_F(BackgroundSyncControllerImplTest,
GetNextEventDelayWithSiteEngagementPenalty) {
controller_ = std::make_unique<BackgroundSyncControllerImpl>(
profile_.GetOffTheRecordProfile());
content::BackgroundSyncParameters sync_parameters;
int64_t min_gap_between_periodic_sync_events_ms =
sync_parameters.min_periodic_sync_events_interval.InMilliseconds();
content::BackgroundSyncRegistration registration =
MakeBackgroundSyncRegistration(
min_gap_between_periodic_sync_events_ms,
/*num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC);
SiteEngagementScore::SetParamValuesForTesting();
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(
GURL(kExampleUrl), SiteEngagementScore::GetMediumEngagementBoundary());
// Medium engagement.
base::TimeDelta delay = controller_->GetNextEventDelay(
registration, &sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(
delay,
base::TimeDelta::FromMilliseconds(
min_gap_between_periodic_sync_events_ms *
BackgroundSyncControllerImpl::kEngagementLevelLowOrMediumPenalty));
// Low engagement.
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(
GURL(kExampleUrl),
SiteEngagementScore::GetMediumEngagementBoundary() - 1);
delay = controller_->GetNextEventDelay(registration, &sync_parameters,
base::TimeDelta::Max());
EXPECT_EQ(
delay,
base::TimeDelta::FromMilliseconds(
min_gap_between_periodic_sync_events_ms *
BackgroundSyncControllerImpl::kEngagementLevelLowOrMediumPenalty));
// Minimal engagement.
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(GURL(kExampleUrl),
0.5);
delay = controller_->GetNextEventDelay(registration, &sync_parameters,
base::TimeDelta::Max());
EXPECT_EQ(delay,
base::TimeDelta::FromMilliseconds(
min_gap_between_periodic_sync_events_ms *
BackgroundSyncControllerImpl::kEngagementLevelMinimalPenalty));
// No engagement.
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(GURL(kExampleUrl),
0);
delay = controller_->GetNextEventDelay(registration, &sync_parameters,
base::TimeDelta::Max());
EXPECT_EQ(delay, base::TimeDelta::Max());
}
TEST_F(BackgroundSyncControllerImplTest, MaxFrequencyForOrigin) {
controller_ = std::make_unique<BackgroundSyncControllerImpl>(
profile_.GetOffTheRecordProfile());
content::BackgroundSyncParameters sync_parameters;
url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
SiteEngagementScore::SetParamValuesForTesting();
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(
GURL(kExampleUrl), SiteEngagementScore::GetHighEngagementBoundary());
// Periodic Sync: zero attempts.
// |min_interval| < kMinGapBetweenPeriodicSyncEvents.
base::TimeDelta delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay, sync_parameters.min_periodic_sync_events_interval);
// Periodic Sync: zero attempts.
// |min_interval| > kMinGapBetweenPeriodicSyncEvents.
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kLargerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay, kLargerThanMinGapExpectedDelay);
// Periodic Sync: zero attempts.
// |min_interval| a multiple of kMinGapBetweenPeriodicSyncEvents.
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ 2 *
kLargerThanMinGapExpectedDelay.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay, 2 * kLargerThanMinGapExpectedDelay);
// Periodic Sync: zero attempts.
// |min_interval| is zero.
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ 0,
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay, sync_parameters.min_periodic_sync_events_interval);
}
TEST_F(BackgroundSyncControllerImplTest, CrossRegistrationLimitsForOrigin) {
controller_ = std::make_unique<BackgroundSyncControllerImpl>(
profile_.GetOffTheRecordProfile());
content::BackgroundSyncParameters sync_parameters;
url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
SiteEngagementScore::SetParamValuesForTesting();
SiteEngagementService::Get(&profile_)->ResetBaseScoreForURL(
GURL(kExampleUrl), SiteEngagementScore::GetHighEngagementBoundary());
// Periodic Sync: zero attempts.
// |min_interval| < kMinGapBetweenPeriodicSyncEvents.
// No other event scheduled.
base::TimeDelta delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::Max());
EXPECT_EQ(delay, sync_parameters.min_periodic_sync_events_interval);
// Periodic Sync: zero attempts.
// |min_interval| < kMinGapBetweenPeriodicSyncEvents.
// Time till next event is zero.
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta());
EXPECT_EQ(delay, sync_parameters.min_periodic_sync_events_interval);
// Periodic Sync: zero attempts.
// |min_interval| < kMinGapBetweenPeriodicSyncEvents.
// Time till next event > kMinGapBetweenPeriodicSyncEvents.
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, kLargerThanMinGap);
EXPECT_EQ(delay, kLargerThanMinGap);
// Periodic Sync: zero attempts.
// |min_interval| < kMinGapBetweenPeriodicSyncEvents.
// delay < time_till_next_event - min_gap_for_origin
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::FromHours(24));
EXPECT_EQ(delay, sync_parameters.min_periodic_sync_events_interval);
// Periodic Sync: zero attempts.
// |min_interval| < kMinGapBetweenPeriodicSyncEvents.
// time_till_next_event - min_gap_for_origin < delay < time_till_next_event +
// min_gap_for_origin
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kSmallerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::FromHours(1));
EXPECT_EQ(delay, sync_parameters.min_periodic_sync_events_interval +
base::TimeDelta::FromHours(1));
// Periodic Sync: zero attempts.
// |min_interval| < kMinGapBetweenPeriodicSyncEvents.
// delay > time_till_next_event + min_gap_for_origin
delay = controller_->GetNextEventDelay(
MakeBackgroundSyncRegistration(
/* min_interval= */ kLargerThanMinGap.InMilliseconds(),
/* num_attempts= */ 0, blink::mojom::BackgroundSyncType::PERIODIC),
&sync_parameters, base::TimeDelta::FromHours(1));
EXPECT_EQ(delay, kLargerThanMinGapExpectedDelay);
}
} // namespace