text: // 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 "components/sync/engine/backoff_delay_provider.h"
  
  #include <memory>
  
  #include "components/sync/base/syncer_error.h"
  #include "components/sync/engine/cycle/model_neutral_state.h"
  #include "components/sync/engine/polling_constants.h"
  #include "net/base/net_errors.h"
  #include "net/http/http_status_code.h"
  #include "testing/gmock/include/gmock/gmock.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace syncer {
  
  namespace {
  
  using base::TimeDelta;
  using testing::Gt;
  using testing::Lt;
  
  TEST(BackoffDelayProviderTest, GetRecommendedDelay) {
    std::unique_ptr<BackoffDelayProvider> delay(
        BackoffDelayProvider::FromDefaults());
    EXPECT_EQ(TimeDelta::FromSeconds(1),
              delay->GetDelay(TimeDelta::FromSeconds(0)));
    EXPECT_LE(TimeDelta::FromSeconds(1),
              delay->GetDelay(TimeDelta::FromSeconds(1)));
    EXPECT_LE(TimeDelta::FromSeconds(50),
              delay->GetDelay(TimeDelta::FromSeconds(50)));
    EXPECT_LE(TimeDelta::FromSeconds(10),
              delay->GetDelay(TimeDelta::FromSeconds(10)));
    EXPECT_EQ(kMaxBackoffTime, delay->GetDelay(kMaxBackoffTime));
    EXPECT_EQ(kMaxBackoffTime,
              delay->GetDelay(kMaxBackoffTime + TimeDelta::FromSeconds(1)));
  }
  
  TEST(BackoffDelayProviderTest, GetInitialDelay) {
    std::unique_ptr<BackoffDelayProvider> delay(
        BackoffDelayProvider::FromDefaults());
    ModelNeutralState state;
    state.last_get_key_result =
        SyncerError::HttpError(net::HTTP_INTERNAL_SERVER_ERROR);
    EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
  
    state.last_get_key_result = SyncerError();
    state.last_download_updates_result =
        SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result =
        SyncerError::NetworkConnectionUnavailable(net::ERR_FAILED);
    EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result =
        SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR);
    EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result =
        SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED);
    EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result =
        SyncerError(SyncerError::DATATYPE_TRIGGERED_RETRY);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result = SyncerError(SyncerError::SYNCER_OK);
    state.commit_result = SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  
    state.commit_result =
        SyncerError::NetworkConnectionUnavailable(net::ERR_FAILED);
    EXPECT_EQ(kInitialBackoffRetryTime, delay->GetInitialDelay(state));
  
    state.commit_result = SyncerError(SyncerError::SERVER_RETURN_CONFLICT);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  }
  
  TEST(BackoffDelayProviderTest, GetInitialDelayWithOverride) {
    std::unique_ptr<BackoffDelayProvider> delay(
        BackoffDelayProvider::WithShortInitialRetryOverride());
    ModelNeutralState state;
    state.last_get_key_result =
        SyncerError::HttpError(net::HTTP_INTERNAL_SERVER_ERROR);
    EXPECT_EQ(kInitialBackoffShortRetryTime, delay->GetInitialDelay(state));
  
    state.last_get_key_result = SyncerError();
    state.last_download_updates_result =
        SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result =
        SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR);
    EXPECT_EQ(kInitialBackoffShortRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result =
        SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED);
    EXPECT_EQ(kInitialBackoffShortRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result =
        SyncerError(SyncerError::DATATYPE_TRIGGERED_RETRY);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  
    state.last_download_updates_result = SyncerError(SyncerError::SYNCER_OK);
    state.commit_result = SyncerError(SyncerError::SERVER_RETURN_MIGRATION_DONE);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  
    state.commit_result = SyncerError(SyncerError::SERVER_RETURN_CONFLICT);
    EXPECT_EQ(kInitialBackoffImmediateRetryTime, delay->GetInitialDelay(state));
  }
  
  // This rules out accidents with the constants.
  TEST(BackoffDelayProviderTest, GetExponentiallyIncreasingDelay) {
    std::unique_ptr<BackoffDelayProvider> delay_provider(
        BackoffDelayProvider::FromDefaults());
  
    ASSERT_THAT(kBackoffMultiplyFactor, Gt(1.0));
    // Even when the jitter is negative, the delay should grow (overall
    // multiplicative factor bigger than 1).
    ASSERT_THAT(kBackoffJitterFactor, Lt(kBackoffMultiplyFactor - 1.0));
  
    const TimeDelta delay0 = TimeDelta::FromSeconds(1);
    const TimeDelta delay1_min =
        delay_provider->GetDelayForTesting(delay0, /*jitter_sign=*/-1);
    const TimeDelta delay2_min =
        delay_provider->GetDelayForTesting(delay1_min, /*jitter_sign=*/-1);
    const TimeDelta delay1_max =
        delay_provider->GetDelayForTesting(delay0, /*jitter_sign=*/1);
    const TimeDelta delay2_max =
        delay_provider->GetDelayForTesting(delay1_max, /*jitter_sign=*/1);
  
    ASSERT_THAT(delay1_min, Lt(delay1_max));
    ASSERT_THAT(delay2_min, Lt(delay2_max));
  
    // The minimum value should increase faster than linearly.
    EXPECT_THAT(delay1_min, Gt(delay0));
    EXPECT_THAT(delay2_min, Gt(delay1_min));
    EXPECT_THAT(delay2_min - delay1_min, Gt(delay1_min - delay0));
  
    // The maximum value should increase faster than linearly.
    EXPECT_THAT(delay1_max, Gt(delay0));
    EXPECT_THAT(delay2_max, Gt(delay1_max));
    EXPECT_THAT(delay2_max - delay1_max, Gt(delay1_max - delay0));
  }
  
  }  // namespace
  
  }  // namespace syncer
  