1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "sync/engine/backoff_delay_provider.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "base/time/time.h"
9#include "sync/internal_api/public/engine/polling_constants.h"
10#include "sync/internal_api/public/sessions/model_neutral_state.h"
11#include "sync/internal_api/public/util/syncer_error.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14using base::TimeDelta;
15
16namespace syncer {
17
18class BackoffDelayProviderTest : public testing::Test {};
19
20TEST_F(BackoffDelayProviderTest, GetRecommendedDelay) {
21  scoped_ptr<BackoffDelayProvider> delay(BackoffDelayProvider::FromDefaults());
22  EXPECT_EQ(TimeDelta::FromSeconds(1),
23            delay->GetDelay(TimeDelta::FromSeconds(0)));
24  EXPECT_LE(TimeDelta::FromSeconds(1),
25            delay->GetDelay(TimeDelta::FromSeconds(1)));
26  EXPECT_LE(TimeDelta::FromSeconds(50),
27            delay->GetDelay(TimeDelta::FromSeconds(50)));
28  EXPECT_LE(TimeDelta::FromSeconds(10),
29            delay->GetDelay(TimeDelta::FromSeconds(10)));
30  EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
31            delay->GetDelay(TimeDelta::FromSeconds(kMaxBackoffSeconds)));
32  EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
33            delay->GetDelay(TimeDelta::FromSeconds(kMaxBackoffSeconds + 1)));
34}
35
36TEST_F(BackoffDelayProviderTest, GetInitialDelay) {
37  scoped_ptr<BackoffDelayProvider> delay(BackoffDelayProvider::FromDefaults());
38  sessions::ModelNeutralState state;
39  state.last_get_key_result = SYNC_SERVER_ERROR;
40  EXPECT_EQ(kInitialBackoffRetrySeconds,
41            delay->GetInitialDelay(state).InSeconds());
42
43  state.last_get_key_result = UNSET;
44  state.last_download_updates_result = SERVER_RETURN_MIGRATION_DONE;
45  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
46            delay->GetInitialDelay(state).InSeconds());
47
48  state.last_download_updates_result = NETWORK_CONNECTION_UNAVAILABLE;
49  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
50            delay->GetInitialDelay(state).InSeconds());
51
52  state.last_download_updates_result = SERVER_RETURN_TRANSIENT_ERROR;
53  EXPECT_EQ(kInitialBackoffRetrySeconds,
54            delay->GetInitialDelay(state).InSeconds());
55
56  state.last_download_updates_result = SERVER_RESPONSE_VALIDATION_FAILED;
57  EXPECT_EQ(kInitialBackoffRetrySeconds,
58            delay->GetInitialDelay(state).InSeconds());
59
60  state.last_download_updates_result = DATATYPE_TRIGGERED_RETRY;
61  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
62            delay->GetInitialDelay(state).InSeconds());
63
64  state.last_download_updates_result = SYNCER_OK;
65  // Note that updating credentials triggers a canary job, trumping
66  // the initial delay, but in theory we still expect this function to treat
67  // it like any other error in the system (except migration).
68  state.commit_result = SERVER_RETURN_INVALID_CREDENTIAL;
69  EXPECT_EQ(kInitialBackoffRetrySeconds,
70            delay->GetInitialDelay(state).InSeconds());
71
72  state.commit_result = SERVER_RETURN_MIGRATION_DONE;
73  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
74            delay->GetInitialDelay(state).InSeconds());
75
76  state.commit_result = NETWORK_CONNECTION_UNAVAILABLE;
77  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
78            delay->GetInitialDelay(state).InSeconds());
79
80  state.commit_result = SERVER_RETURN_CONFLICT;
81  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
82            delay->GetInitialDelay(state).InSeconds());
83}
84
85TEST_F(BackoffDelayProviderTest, GetInitialDelayWithOverride) {
86  scoped_ptr<BackoffDelayProvider> delay(
87      BackoffDelayProvider::WithShortInitialRetryOverride());
88  sessions::ModelNeutralState state;
89  state.last_get_key_result = SYNC_SERVER_ERROR;
90  EXPECT_EQ(kInitialBackoffShortRetrySeconds,
91            delay->GetInitialDelay(state).InSeconds());
92
93  state.last_get_key_result = UNSET;
94  state.last_download_updates_result = SERVER_RETURN_MIGRATION_DONE;
95  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
96            delay->GetInitialDelay(state).InSeconds());
97
98  state.last_download_updates_result = SERVER_RETURN_TRANSIENT_ERROR;
99  EXPECT_EQ(kInitialBackoffShortRetrySeconds,
100            delay->GetInitialDelay(state).InSeconds());
101
102  state.last_download_updates_result = SERVER_RESPONSE_VALIDATION_FAILED;
103  EXPECT_EQ(kInitialBackoffShortRetrySeconds,
104            delay->GetInitialDelay(state).InSeconds());
105
106  state.last_download_updates_result = DATATYPE_TRIGGERED_RETRY;
107  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
108            delay->GetInitialDelay(state).InSeconds());
109
110  state.last_download_updates_result = SYNCER_OK;
111  // Note that updating credentials triggers a canary job, trumping
112  // the initial delay, but in theory we still expect this function to treat
113  // it like any other error in the system (except migration).
114  state.commit_result = SERVER_RETURN_INVALID_CREDENTIAL;
115  EXPECT_EQ(kInitialBackoffShortRetrySeconds,
116            delay->GetInitialDelay(state).InSeconds());
117
118  state.commit_result = SERVER_RETURN_MIGRATION_DONE;
119  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
120            delay->GetInitialDelay(state).InSeconds());
121
122  state.commit_result = SERVER_RETURN_CONFLICT;
123  EXPECT_EQ(kInitialBackoffImmediateRetrySeconds,
124            delay->GetInitialDelay(state).InSeconds());
125}
126
127}  // namespace syncer
128