1 // Copyright 2014 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 "chrome/browser/sync/startup_controller.h"
6
7 #include "base/command_line.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/time/time.h"
11 #include "chrome/browser/defaults.h"
12 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
13 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
14 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
15 #include "chrome/browser/sync/supervised_user_signin_manager_wrapper.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "components/sync_driver/sync_prefs.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace browser_sync {
22
23 static const char kTestUser[] = "test@gmail.com";
24 static const char kTestToken[] = "testToken";
25
26 // These are coupled to the implementation of StartupController's
27 // GetBackendInitializationStateString which is used by about:sync. We use it
28 // as a convenient way to verify internal state and that the class is
29 // outputting the correct values for the debug string.
30 static const char kStateStringStarted[] = "Started";
31 static const char kStateStringDeferred[] = "Deferred";
32 static const char kStateStringNotStarted[] = "Not started";
33
34 class FakeSupervisedUserSigninManagerWrapper
35 : public SupervisedUserSigninManagerWrapper {
36 public:
FakeSupervisedUserSigninManagerWrapper()37 FakeSupervisedUserSigninManagerWrapper()
38 : SupervisedUserSigninManagerWrapper(NULL, NULL) {}
GetEffectiveUsername() const39 virtual std::string GetEffectiveUsername() const OVERRIDE {
40 return account_;
41 }
42
GetAccountIdToUse() const43 virtual std::string GetAccountIdToUse() const OVERRIDE {
44 return account_;
45 }
46
set_account(const std::string & account)47 void set_account(const std::string& account) { account_ = account; }
48
49 private:
50 std::string account_;
51 };
52
53 class StartupControllerTest : public testing::Test {
54 public:
StartupControllerTest()55 StartupControllerTest() : started_(false) {}
56
SetUp()57 virtual void SetUp() OVERRIDE {
58 profile_.reset(new TestingProfile());
59 sync_prefs_.reset(new sync_driver::SyncPrefs(profile_->GetPrefs()));
60 token_service_.reset(static_cast<FakeProfileOAuth2TokenService*>(
61 BuildFakeProfileOAuth2TokenService(profile_.get())));
62 signin_.reset(new FakeSupervisedUserSigninManagerWrapper());
63
64 ProfileSyncServiceStartBehavior behavior =
65 browser_defaults::kSyncAutoStarts ? AUTO_START : MANUAL_START;
66 base::Closure fake_start_backend = base::Bind(
67 &StartupControllerTest::FakeStartBackend, base::Unretained(this));
68 controller_.reset(new StartupController(behavior, token_service(),
69 sync_prefs_.get(), signin_.get(),
70 fake_start_backend));
71 controller_->Reset(syncer::UserTypes());
72 controller_->OverrideFallbackTimeoutForTest(
73 base::TimeDelta::FromSeconds(0));
74 }
75
TearDown()76 virtual void TearDown() OVERRIDE {
77 controller_.reset();
78 signin_.reset();
79 token_service_->Shutdown();
80 token_service_.reset();
81 sync_prefs_.reset();
82 started_ = false;
83 }
84
FakeStartBackend()85 void FakeStartBackend() {
86 started_ = true;
87 }
88
started() const89 bool started() const { return started_; }
clear_started()90 void clear_started() { started_ = false; }
controller()91 StartupController* controller() { return controller_.get(); }
signin()92 FakeSupervisedUserSigninManagerWrapper* signin() { return signin_.get(); }
token_service()93 FakeProfileOAuth2TokenService* token_service() {
94 return token_service_.get();
95 }
sync_prefs()96 sync_driver::SyncPrefs* sync_prefs() { return sync_prefs_.get(); }
profile()97 Profile* profile() { return profile_.get(); }
98
99 private:
100 bool started_;
101 base::MessageLoop message_loop_;
102 scoped_ptr<StartupController> controller_;
103 scoped_ptr<FakeSupervisedUserSigninManagerWrapper> signin_;
104 scoped_ptr<FakeProfileOAuth2TokenService> token_service_;
105 scoped_ptr<sync_driver::SyncPrefs> sync_prefs_;
106 scoped_ptr<TestingProfile> profile_;
107 };
108
109 // Test that sync doesn't start until all conditions are met.
TEST_F(StartupControllerTest,Basic)110 TEST_F(StartupControllerTest, Basic) {
111 controller()->TryStart();
112 EXPECT_FALSE(started());
113 sync_prefs()->SetSyncSetupCompleted();
114 controller()->TryStart();
115 EXPECT_FALSE(started());
116 signin()->set_account(kTestUser);
117 controller()->TryStart();
118 EXPECT_FALSE(started());
119 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
120 const bool deferred_start = !CommandLine::ForCurrentProcess()->
121 HasSwitch(switches::kSyncDisableDeferredStartup);
122 controller()->TryStart();
123 EXPECT_EQ(!deferred_start, started());
124 std::string state(controller()->GetBackendInitializationStateString());
125 EXPECT_TRUE(deferred_start ? state == kStateStringDeferred :
126 state == kStateStringStarted);
127 }
128
129 // Test that sync doesn't when suppressed even if all other conditons are met.
TEST_F(StartupControllerTest,Suppressed)130 TEST_F(StartupControllerTest, Suppressed) {
131 sync_prefs()->SetSyncSetupCompleted();
132 sync_prefs()->SetStartSuppressed(true);
133 signin()->set_account(kTestUser);
134 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
135 controller()->TryStart();
136 EXPECT_FALSE(started());
137 EXPECT_EQ(kStateStringNotStarted,
138 controller()->GetBackendInitializationStateString());
139 }
140
141 // Test that sync doesn't when managed even if all other conditons are met.
TEST_F(StartupControllerTest,Managed)142 TEST_F(StartupControllerTest, Managed) {
143 sync_prefs()->SetSyncSetupCompleted();
144 sync_prefs()->SetManagedForTest(true);
145 signin()->set_account(kTestUser);
146 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
147 controller()->TryStart();
148 EXPECT_FALSE(started());
149 EXPECT_EQ(kStateStringNotStarted,
150 controller()->GetBackendInitializationStateString());
151 }
152
153 // Test that sync doesn't start until all conditions are met and a
154 // data type triggers sync startup.
TEST_F(StartupControllerTest,DataTypeTriggered)155 TEST_F(StartupControllerTest, DataTypeTriggered) {
156 sync_prefs()->SetSyncSetupCompleted();
157 signin()->set_account(kTestUser);
158 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
159 controller()->TryStart();
160 EXPECT_FALSE(started());
161 EXPECT_EQ(kStateStringDeferred,
162 controller()->GetBackendInitializationStateString());
163 controller()->OnDataTypeRequestsSyncStartup(syncer::SESSIONS);
164 EXPECT_TRUE(started());
165 EXPECT_EQ(kStateStringStarted,
166 controller()->GetBackendInitializationStateString());
167
168 // The fallback timer shouldn't result in another invocation of the closure
169 // we passed to the StartupController.
170 clear_started();
171 base::RunLoop().RunUntilIdle();
172 EXPECT_FALSE(started());
173 }
174
175 // Test that the fallback timer starts sync in the event all
176 // conditions are met and no data type requests sync.
TEST_F(StartupControllerTest,FallbackTimer)177 TEST_F(StartupControllerTest, FallbackTimer) {
178 sync_prefs()->SetSyncSetupCompleted();
179 signin()->set_account(kTestUser);
180 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
181 controller()->TryStart();
182 EXPECT_FALSE(started());
183 base::RunLoop().RunUntilIdle();
184 EXPECT_TRUE(started());
185 }
186
187 // Test that we start immediately if sessions is disabled.
TEST_F(StartupControllerTest,NoDeferralWithoutSessionsSync)188 TEST_F(StartupControllerTest, NoDeferralWithoutSessionsSync) {
189 syncer::ModelTypeSet types(syncer::UserTypes());
190 // Disabling sessions means disabling 4 types due to groupings.
191 types.Remove(syncer::SESSIONS);
192 types.Remove(syncer::PROXY_TABS);
193 types.Remove(syncer::TYPED_URLS);
194 types.Remove(syncer::SUPERVISED_USER_SETTINGS);
195 sync_prefs()->SetKeepEverythingSynced(false);
196 sync_prefs()->SetPreferredDataTypes(syncer::UserTypes(), types);
197 controller()->Reset(syncer::UserTypes());
198 sync_prefs()->SetSyncSetupCompleted();
199 signin()->set_account(kTestUser);
200 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
201 controller()->TryStart();
202 EXPECT_TRUE(started());
203 }
204
205 // Sanity check that the fallback timer doesn't fire before startup
206 // conditions are met.
TEST_F(StartupControllerTest,FallbackTimerWaits)207 TEST_F(StartupControllerTest, FallbackTimerWaits) {
208 controller()->TryStart();
209 EXPECT_FALSE(started());
210 base::RunLoop().RunUntilIdle();
211 EXPECT_FALSE(started());
212 }
213
214 // Test that sync starts when the user first asks to setup sync (which
215 // may be implicit due to the platform).
TEST_F(StartupControllerTest,FirstSetup)216 TEST_F(StartupControllerTest, FirstSetup) {
217 signin()->set_account(kTestUser);
218 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
219 controller()->TryStart();
220
221 if (browser_defaults::kSyncAutoStarts) {
222 EXPECT_TRUE(started());
223 } else {
224 controller()->set_setup_in_progress(true);
225 controller()->TryStart();
226 EXPECT_TRUE(started());
227 }
228 }
229
TEST_F(StartupControllerTest,Reset)230 TEST_F(StartupControllerTest, Reset) {
231 sync_prefs()->SetSyncSetupCompleted();
232 signin()->set_account(kTestUser);
233 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
234 controller()->TryStart();
235 const bool deferred_start = !CommandLine::ForCurrentProcess()->
236 HasSwitch(switches::kSyncDisableDeferredStartup);
237 EXPECT_EQ(!deferred_start, started());
238 controller()->OnDataTypeRequestsSyncStartup(syncer::SESSIONS);
239 EXPECT_TRUE(started());
240 clear_started();
241 controller()->Reset(syncer::UserTypes());
242 EXPECT_FALSE(started());
243 controller()->TryStart();
244 // Restart is not deferred.
245 EXPECT_TRUE(started());
246 }
247
248 // Test that setup-in-progress tracking is persistent across a Reset.
TEST_F(StartupControllerTest,ResetDuringSetup)249 TEST_F(StartupControllerTest, ResetDuringSetup) {
250 signin()->set_account(kTestUser);
251 token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
252
253 // Simulate UI telling us setup is in progress.
254 controller()->set_setup_in_progress(true);
255
256 // This could happen if the UI triggers a stop-syncing permanently call.
257 controller()->Reset(syncer::UserTypes());
258
259 // From the UI's point of view, setup is still in progress.
260 EXPECT_TRUE(controller()->setup_in_progress());
261 }
262
263 } // namespace browser_sync
264