Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: chrome/browser/sync/backend_migrator_unittest.cc

Issue 7655055: [Sync] Make BackendMigrator not wait for full sync cycles (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync to head Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/backend_migrator.h" 5 #include "chrome/browser/sync/backend_migrator.h"
6 6
7 #include "base/message_loop.h"
7 #include "chrome/browser/sync/glue/data_type_manager_mock.h" 8 #include "chrome/browser/sync/glue/data_type_manager_mock.h"
8 #include "chrome/browser/sync/profile_sync_service_mock.h" 9 #include "chrome/browser/sync/profile_sync_service_mock.h"
9 #include "chrome/browser/sync/sessions/session_state.h" 10 #include "chrome/browser/sync/sessions/session_state.h"
10 #include "chrome/common/chrome_notification_types.h" 11 #include "chrome/common/chrome_notification_types.h"
11 #include "chrome/test/base/testing_browser_process_test.h" 12 #include "chrome/test/base/testing_browser_process_test.h"
12 #include "testing/gmock/include/gmock/gmock.h" 13 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h" 14 #include "testing/gtest/include/gtest/gtest.h"
14 15
15 using ::testing::_; 16 using ::testing::_;
16 using ::testing::Eq; 17 using ::testing::Eq;
(...skipping 17 matching lines...) Expand all
34 Mock::VerifyAndClear(manager()); 35 Mock::VerifyAndClear(manager());
35 Mock::VerifyAndClear(&service_); 36 Mock::VerifyAndClear(&service_);
36 preferred_types_.insert(syncable::BOOKMARKS); 37 preferred_types_.insert(syncable::BOOKMARKS);
37 preferred_types_.insert(syncable::PREFERENCES); 38 preferred_types_.insert(syncable::PREFERENCES);
38 preferred_types_.insert(syncable::AUTOFILL); 39 preferred_types_.insert(syncable::AUTOFILL);
39 40
40 ON_CALL(service_, GetPreferredDataTypes(_)). 41 ON_CALL(service_, GetPreferredDataTypes(_)).
41 WillByDefault(SetArgumentPointee<0>(preferred_types_)); 42 WillByDefault(SetArgumentPointee<0>(preferred_types_));
42 } 43 }
43 44
44 void ReturnEmptyProgressMarkersInSnapshot() {
45 ReturnNonEmptyProgressMarkersInSnapshot(syncable::ModelTypeSet());
46 }
47
48 void ReturnNonEmptyProgressMarkersInSnapshot(
49 const syncable::ModelTypeSet& for_types) {
50 std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
51 for (syncable::ModelTypeSet::const_iterator it = for_types.begin();
52 it != for_types.end(); ++it) {
53 download_progress_markers[*it] = "foobar";
54 }
55
56 snap_.reset(new SyncSessionSnapshot(SyncerStatus(), ErrorCounters(),
57 0, false, syncable::ModelTypeBitSet(), download_progress_markers,
58 false, false, 0, 0, 0, false, sessions::SyncSourceInfo(), 0,
59 base::Time::Now()));
60 EXPECT_CALL(service_, GetLastSessionSnapshot())
61 .WillOnce(Return(snap_.get()));
62 }
63
64 void SendConfigureDone(DataTypeManager::ConfigureStatus status, 45 void SendConfigureDone(DataTypeManager::ConfigureStatus status,
65 const syncable::ModelTypeSet& types) { 46 const syncable::ModelTypeSet& types) {
66 if (status == DataTypeManager::OK) { 47 if (status == DataTypeManager::OK) {
67 DataTypeManager::ConfigureResult result(status, types); 48 DataTypeManager::ConfigureResult result(status, types);
68 NotificationService::current()->Notify( 49 NotificationService::current()->Notify(
69 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, 50 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
70 Source<DataTypeManager>(&manager_), 51 Source<DataTypeManager>(&manager_),
71 Details<const DataTypeManager::ConfigureResult>(&result)); 52 Details<const DataTypeManager::ConfigureResult>(&result));
72 } else { 53 } else {
73 DataTypeManager::ConfigureResult result( 54 DataTypeManager::ConfigureResult result(
74 status, 55 status,
75 types, 56 types,
76 syncable::ModelTypeSet(), 57 syncable::ModelTypeSet(),
77 FROM_HERE); 58 FROM_HERE);
78 NotificationService::current()->Notify( 59 NotificationService::current()->Notify(
79 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, 60 chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
80 Source<DataTypeManager>(&manager_), 61 Source<DataTypeManager>(&manager_),
81 Details<const DataTypeManager::ConfigureResult>(&result)); 62 Details<const DataTypeManager::ConfigureResult>(&result));
82 } 63 }
64 message_loop_.RunAllPending();
83 } 65 }
84 66
85 ProfileSyncService* service() { return &service_; } 67 ProfileSyncService* service() { return &service_; }
86 DataTypeManagerMock* manager() { return &manager_; } 68 DataTypeManagerMock* manager() { return &manager_; }
87 const syncable::ModelTypeSet& preferred_types() { return preferred_types_; } 69 const syncable::ModelTypeSet& preferred_types() { return preferred_types_; }
88 void RemovePreferredType(syncable::ModelType type) { 70 void RemovePreferredType(syncable::ModelType type) {
89 preferred_types_.erase(type); 71 preferred_types_.erase(type);
90 Mock::VerifyAndClear(&service_); 72 Mock::VerifyAndClear(&service_);
91 ON_CALL(service_, GetPreferredDataTypes(_)). 73 ON_CALL(service_, GetPreferredDataTypes(_)).
92 WillByDefault(SetArgumentPointee<0>(preferred_types_)); 74 WillByDefault(SetArgumentPointee<0>(preferred_types_));
93 } 75 }
94 private: 76 private:
95 scoped_ptr<SyncSessionSnapshot> snap_; 77 MessageLoop message_loop_;
96 syncable::ModelTypeSet preferred_types_; 78 syncable::ModelTypeSet preferred_types_;
97 NiceMock<ProfileSyncServiceMock> service_; 79 NiceMock<ProfileSyncServiceMock> service_;
98 NiceMock<DataTypeManagerMock> manager_; 80 NiceMock<DataTypeManagerMock> manager_;
99 }; 81 };
100 82
101 // Test that in the normal case a migration does transition through each state 83 // Test that in the normal case a migration does transition through each state
102 // and wind up back in IDLE. 84 // and wind up back in IDLE.
103 TEST_F(BackendMigratorTest, Sanity) { 85 TEST_F(BackendMigratorTest, Sanity) {
104 BackendMigrator migrator(service(), manager()); 86 BackendMigrator migrator(service(), manager());
105 syncable::ModelTypeSet to_migrate, difference; 87 syncable::ModelTypeSet to_migrate, difference;
106 to_migrate.insert(syncable::PREFERENCES); 88 to_migrate.insert(syncable::PREFERENCES);
107 difference.insert(syncable::AUTOFILL); 89 difference.insert(syncable::AUTOFILL);
108 difference.insert(syncable::BOOKMARKS); 90 difference.insert(syncable::BOOKMARKS);
109 91
110 EXPECT_CALL(*manager(), state()) 92 EXPECT_CALL(*manager(), state())
111 .WillOnce(Return(DataTypeManager::CONFIGURED)); 93 .WillOnce(Return(DataTypeManager::CONFIGURED));
112 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION)); 94 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
95 .Times(2);
113 96
114 migrator.MigrateTypes(to_migrate); 97 migrator.MigrateTypes(to_migrate);
115 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 98 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
116 99
117 SendConfigureDone(DataTypeManager::OK, difference); 100 SendConfigureDone(DataTypeManager::OK, difference);
118 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
119
120 ReturnEmptyProgressMarkersInSnapshot();
121 EXPECT_CALL(*manager(), Configure(preferred_types(),
122 sync_api::CONFIGURE_REASON_MIGRATION));
123 migrator.OnStateChanged();
124 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state()); 101 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
125 102
126 SendConfigureDone(DataTypeManager::OK, preferred_types()); 103 SendConfigureDone(DataTypeManager::OK, preferred_types());
127 EXPECT_EQ(BackendMigrator::IDLE, migrator.state()); 104 EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
128 } 105 }
129 106
130 // Test that in the normal case with Nigori a migration transitions through 107 // Test that in the normal case with Nigori a migration transitions through
131 // each state and wind up back in IDLE. 108 // each state and wind up back in IDLE.
132 TEST_F(BackendMigratorTest, MigrateNigori) { 109 TEST_F(BackendMigratorTest, MigrateNigori) {
133 BackendMigrator migrator(service(), manager()); 110 BackendMigrator migrator(service(), manager());
134 syncable::ModelTypeSet to_migrate, difference; 111 syncable::ModelTypeSet to_migrate, difference;
135 to_migrate.insert(syncable::NIGORI); 112 to_migrate.insert(syncable::NIGORI);
136 difference.insert(syncable::AUTOFILL); 113 difference.insert(syncable::AUTOFILL);
137 difference.insert(syncable::BOOKMARKS); 114 difference.insert(syncable::BOOKMARKS);
138 115
139 EXPECT_CALL(*manager(), state()) 116 EXPECT_CALL(*manager(), state())
140 .WillOnce(Return(DataTypeManager::CONFIGURED)); 117 .WillOnce(Return(DataTypeManager::CONFIGURED));
141 118
142 EXPECT_CALL(*manager(), ConfigureWithoutNigori(_, 119 EXPECT_CALL(*manager(), ConfigureWithoutNigori(_,
143 sync_api::CONFIGURE_REASON_MIGRATION)); 120 sync_api::CONFIGURE_REASON_MIGRATION));
144 121
145 migrator.MigrateTypes(to_migrate); 122 migrator.MigrateTypes(to_migrate);
146 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 123 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
147 124
148 SendConfigureDone(DataTypeManager::OK, difference); 125 SendConfigureDone(DataTypeManager::OK, difference);
149 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
150
151 ReturnEmptyProgressMarkersInSnapshot();
152 EXPECT_CALL(*manager(), Configure(preferred_types(),
153 sync_api::CONFIGURE_REASON_MIGRATION));
154 migrator.OnStateChanged();
155 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state()); 126 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
156 127
157 SendConfigureDone(DataTypeManager::OK, preferred_types()); 128 SendConfigureDone(DataTypeManager::OK, preferred_types());
158 EXPECT_EQ(BackendMigrator::IDLE, migrator.state()); 129 EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
159 } 130 }
160 131
161 132
162 // Test that the migrator waits for the data type manager to be idle before 133 // Test that the migrator waits for the data type manager to be idle before
163 // starting a migration. 134 // starting a migration.
164 TEST_F(BackendMigratorTest, WaitToStart) { 135 TEST_F(BackendMigratorTest, WaitToStart) {
(...skipping 21 matching lines...) Expand all
186 TEST_F(BackendMigratorTest, RestartMigration) { 157 TEST_F(BackendMigratorTest, RestartMigration) {
187 BackendMigrator migrator(service(), manager()); 158 BackendMigrator migrator(service(), manager());
188 syncable::ModelTypeSet to_migrate1, to_migrate2, bookmarks; 159 syncable::ModelTypeSet to_migrate1, to_migrate2, bookmarks;
189 to_migrate1.insert(syncable::PREFERENCES); 160 to_migrate1.insert(syncable::PREFERENCES);
190 to_migrate2.insert(syncable::AUTOFILL); 161 to_migrate2.insert(syncable::AUTOFILL);
191 bookmarks.insert(syncable::BOOKMARKS); 162 bookmarks.insert(syncable::BOOKMARKS);
192 163
193 EXPECT_CALL(*manager(), state()) 164 EXPECT_CALL(*manager(), state())
194 .WillOnce(Return(DataTypeManager::CONFIGURED)); 165 .WillOnce(Return(DataTypeManager::CONFIGURED));
195 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION)) 166 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
196 .Times(1); 167 .Times(2);
197 migrator.MigrateTypes(to_migrate1); 168 migrator.MigrateTypes(to_migrate1);
198 169
199 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 170 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
200 migrator.MigrateTypes(to_migrate2); 171 migrator.MigrateTypes(to_migrate2);
201 172
202 syncable::ModelTypeSet difference1; 173 syncable::ModelTypeSet difference1;
203 std::set_difference(preferred_types().begin(), preferred_types().end(), 174 std::set_difference(preferred_types().begin(), preferred_types().end(),
204 to_migrate1.begin(), to_migrate1.end(), 175 to_migrate1.begin(), to_migrate1.end(),
205 std::inserter(difference1, difference1.end())); 176 std::inserter(difference1, difference1.end()));
206 177
207 Mock::VerifyAndClearExpectations(manager()); 178 Mock::VerifyAndClearExpectations(manager());
208 EXPECT_CALL(*manager(), state()) 179 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
209 .WillOnce(Return(DataTypeManager::CONFIGURED)); 180 .Times(2);
210 EXPECT_CALL(*manager(), Configure(bookmarks,
211 sync_api::CONFIGURE_REASON_MIGRATION));
212 SendConfigureDone(DataTypeManager::OK, difference1); 181 SendConfigureDone(DataTypeManager::OK, difference1);
213 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 182 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
214 183
215 SendConfigureDone(DataTypeManager::OK, bookmarks); 184 SendConfigureDone(DataTypeManager::OK, bookmarks);
216 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state()); 185 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
217 } 186 }
218 187
219 // Test that an external invocation of Configure(...) during a migration results 188 // Test that an external invocation of Configure(...) during a migration results
220 // in a migration reattempt. 189 // in a migration reattempt.
221 TEST_F(BackendMigratorTest, InterruptedWhileDisablingTypes) { 190 TEST_F(BackendMigratorTest, InterruptedWhileDisablingTypes) {
222 BackendMigrator migrator(service(), manager()); 191 BackendMigrator migrator(service(), manager());
223 syncable::ModelTypeSet to_migrate; 192 syncable::ModelTypeSet to_migrate;
224 syncable::ModelTypeSet difference; 193 syncable::ModelTypeSet difference;
225 to_migrate.insert(syncable::PREFERENCES); 194 to_migrate.insert(syncable::PREFERENCES);
226 difference.insert(syncable::AUTOFILL); 195 difference.insert(syncable::AUTOFILL);
227 difference.insert(syncable::BOOKMARKS); 196 difference.insert(syncable::BOOKMARKS);
228 197
229 EXPECT_CALL(*manager(), state()) 198 EXPECT_CALL(*manager(), state())
230 .WillOnce(Return(DataTypeManager::CONFIGURED)); 199 .WillOnce(Return(DataTypeManager::CONFIGURED));
231 EXPECT_CALL(*manager(), Configure(difference, 200 EXPECT_CALL(*manager(), Configure(difference,
232 sync_api::CONFIGURE_REASON_MIGRATION)); 201 sync_api::CONFIGURE_REASON_MIGRATION));
233 migrator.MigrateTypes(to_migrate); 202 migrator.MigrateTypes(to_migrate);
234 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 203 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
235 204
236 Mock::VerifyAndClearExpectations(manager()); 205 Mock::VerifyAndClearExpectations(manager());
237 EXPECT_CALL(*manager(), state())
238 .WillOnce(Return(DataTypeManager::CONFIGURED));
239 EXPECT_CALL(*manager(), Configure(difference, 206 EXPECT_CALL(*manager(), Configure(difference,
240 sync_api::CONFIGURE_REASON_MIGRATION)); 207 sync_api::CONFIGURE_REASON_MIGRATION));
241 SendConfigureDone(DataTypeManager::OK, preferred_types()); 208 SendConfigureDone(DataTypeManager::OK, preferred_types());
242 209
243 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state()); 210 EXPECT_EQ(BackendMigrator::DISABLING_TYPES, migrator.state());
244 } 211 }
245 212
246 // Test that spurious OnStateChanged events don't confuse the migrator while
247 // it's waiting for disabled types to have been purged from the sync db.
248 TEST_F(BackendMigratorTest, WaitingForPurge) {
249 BackendMigrator migrator(service(), manager());
250 syncable::ModelTypeSet to_migrate, difference;
251 to_migrate.insert(syncable::PREFERENCES);
252 to_migrate.insert(syncable::AUTOFILL);
253 difference.insert(syncable::BOOKMARKS);
254
255 EXPECT_CALL(*manager(), state())
256 .WillOnce(Return(DataTypeManager::CONFIGURED));
257 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION));
258 migrator.MigrateTypes(to_migrate);
259 SendConfigureDone(DataTypeManager::OK, difference);
260 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
261
262 ReturnNonEmptyProgressMarkersInSnapshot(to_migrate);
263 migrator.OnStateChanged();
264 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
265
266 syncable::ModelTypeSet prefs;
267 prefs.insert(syncable::PREFERENCES);
268 ReturnNonEmptyProgressMarkersInSnapshot(prefs);
269 migrator.OnStateChanged();
270 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
271
272 syncable::ModelTypeSet bookmarks;
273 bookmarks.insert(syncable::BOOKMARKS);
274 ReturnNonEmptyProgressMarkersInSnapshot(bookmarks);
275 EXPECT_CALL(*manager(), Configure(preferred_types(),
276 sync_api::CONFIGURE_REASON_MIGRATION));
277 migrator.OnStateChanged();
278 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
279 }
280
281 TEST_F(BackendMigratorTest, MigratedTypeDisabledByUserDuringMigration) { 213 TEST_F(BackendMigratorTest, MigratedTypeDisabledByUserDuringMigration) {
282 BackendMigrator migrator(service(), manager()); 214 BackendMigrator migrator(service(), manager());
283 syncable::ModelTypeSet to_migrate; 215 syncable::ModelTypeSet to_migrate;
284 to_migrate.insert(syncable::PREFERENCES); 216 to_migrate.insert(syncable::PREFERENCES);
285 217
286 EXPECT_CALL(*manager(), state()) 218 EXPECT_CALL(*manager(), state())
287 .WillOnce(Return(DataTypeManager::CONFIGURED)); 219 .WillOnce(Return(DataTypeManager::CONFIGURED));
288 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION)); 220 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
221 .Times(2);
289 migrator.MigrateTypes(to_migrate); 222 migrator.MigrateTypes(to_migrate);
290 223
291 RemovePreferredType(syncable::PREFERENCES); 224 RemovePreferredType(syncable::PREFERENCES);
292 SendConfigureDone(DataTypeManager::OK, preferred_types()); 225 SendConfigureDone(DataTypeManager::OK, preferred_types());
293 EXPECT_EQ(BackendMigrator::WAITING_FOR_PURGE, migrator.state());
294
295 Mock::VerifyAndClearExpectations(manager());
296 ReturnEmptyProgressMarkersInSnapshot();
297 EXPECT_CALL(*manager(), Configure(preferred_types(),
298 sync_api::CONFIGURE_REASON_MIGRATION));
299 migrator.OnStateChanged();
300
301 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state()); 226 EXPECT_EQ(BackendMigrator::REENABLING_TYPES, migrator.state());
302 SendConfigureDone(DataTypeManager::OK, preferred_types()); 227 SendConfigureDone(DataTypeManager::OK, preferred_types());
303 EXPECT_EQ(BackendMigrator::IDLE, migrator.state()); 228 EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
304 } 229 }
305 230
306 TEST_F(BackendMigratorTest, ConfigureFailure) { 231 TEST_F(BackendMigratorTest, ConfigureFailure) {
307 BackendMigrator migrator(service(), manager()); 232 BackendMigrator migrator(service(), manager());
308 syncable::ModelTypeSet to_migrate; 233 syncable::ModelTypeSet to_migrate;
309 to_migrate.insert(syncable::PREFERENCES); 234 to_migrate.insert(syncable::PREFERENCES);
310 235
311 EXPECT_CALL(*manager(), state()) 236 EXPECT_CALL(*manager(), state())
312 .WillOnce(Return(DataTypeManager::CONFIGURED)); 237 .WillOnce(Return(DataTypeManager::CONFIGURED));
313 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION)) 238 EXPECT_CALL(*manager(), Configure(_, sync_api::CONFIGURE_REASON_MIGRATION))
314 .Times(1); 239 .Times(1);
315 migrator.MigrateTypes(to_migrate); 240 migrator.MigrateTypes(to_migrate);
316 SendConfigureDone(DataTypeManager::ABORTED, syncable::ModelTypeSet()); 241 SendConfigureDone(DataTypeManager::ABORTED, syncable::ModelTypeSet());
317 EXPECT_EQ(BackendMigrator::IDLE, migrator.state()); 242 EXPECT_EQ(BackendMigrator::IDLE, migrator.state());
318 } 243 }
319 244
320 }; // namespace browser_sync 245 }; // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698