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

Side by Side Diff: chrome/browser/extensions/extension_settings_sync_unittest.cc

Issue 7747043: WORK IN PROGRESS. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Small change 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "testing/gtest/include/gtest/gtest.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop.h"
14 #include "base/task.h"
15 #include "chrome/browser/extensions/extension_settings.h"
16 #include "chrome/browser/extensions/extension_settings_storage_cache.h"
17 #include "chrome/browser/extensions/extension_settings_noop_storage.h"
18 #include "chrome/browser/extensions/extension_settings_sync_helper.h"
19 #include "chrome/browser/extensions/syncable_extension_settings_storage.h"
20 #include "chrome/browser/sync/api/sync_change_processor.h"
21 #include "content/browser/browser_thread.h"
22
23 namespace {
24
25 // Define macro to get the __LINE__ expansion.
26 #define NEW_CALLBACK(expected) \
27 (new AssertEqualsCallback((expected), __LINE__))
28
29 // SyncChangeProcessor which just records the changes made, accessed after
30 // being converted to the more useful ExtensionSettingSyncData via changes().
31 class MockSyncChangeProcessor : public SyncChangeProcessor {
32 public:
33 virtual SyncError ProcessSyncChanges(
34 const tracked_objects::Location& from_here,
35 const SyncChangeList& change_list) OVERRIDE {
36 for (SyncChangeList::const_iterator it = change_list.begin();
37 it != change_list.end(); ++it) {
38 ExtensionSettingsSyncData data(*it);
39 DCHECK(data.value() != NULL);
40 changes_.push_back(data);
41 }
42 return SyncError();
43 }
44
45 const ExtensionSettingsSyncDataList& changes() { return changes_; }
46
47 void ClearChanges() {
48 changes_.clear();
49 }
50
51 // Returns the only change for a given extension setting. If there is not
52 // exactly 1 change for that key, a test assertion will fail.
53 ExtensionSettingsSyncData GetOnlyChange(
54 const std::string& extension_id, const std::string& key) {
55 ExtensionSettingsSyncDataList matching_changes;
56 for (ExtensionSettingsSyncDataList::iterator it = changes_.begin();
57 it != changes_.end(); ++it) {
58 if (it->extension_id() == extension_id && it->key() == key) {
59 matching_changes.push_back(*it);
60 }
61 }
62 DCHECK_EQ(1u, matching_changes.size()) <<
63 "Not exactly 1 change for " << extension_id << "/" << key <<
64 " (out of " << changes_.size() << ")";
65 return matching_changes[0];
66 }
67
68 private:
69 ExtensionSettingsSyncDataList changes_;
70 };
71
72 // Callback from storage methods which performs the test assertions.
73 // TODO(kalman): share this with extension_settings_storage_unittest somehow.
74 class AssertEqualsCallback : public ExtensionSettingsStorage::Callback {
75 public:
76 AssertEqualsCallback(DictionaryValue* expected, int line)
77 : expected_(expected), line_(line), called_(false) {
78 }
79
80 ~AssertEqualsCallback() {
81 // Need to DCHECK since ASSERT_* can't be used from destructors.
82 DCHECK(called_);
83 }
84
85 virtual void OnSuccess(DictionaryValue* actual) OVERRIDE {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
87 ASSERT_FALSE(called_) << "Callback has already been called";
88 called_ = true;
89 if (expected_ == NULL) {
90 ASSERT_TRUE(actual == NULL) << "Values are different:\n" <<
91 "Line: " << line_ << "\n" <<
92 "Expected: NULL\n" <<
93 "Got: " << GetJson(actual);
94 } else {
95 ASSERT_TRUE(expected_->Equals(actual)) << "Values are different:\n" <<
96 "Line: " << line_ << "\n" <<
97 "Expected: " << GetJson(expected_) <<
98 "Got: " << GetJson(actual);
99 delete actual;
100 }
101 }
102
103 virtual void OnFailure(const std::string& message) OVERRIDE {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105 ASSERT_FALSE(called_) << "Callback has already been called";
106 called_ = true;
107 // No tests allow failure (yet).
108 ASSERT_TRUE(false) << "Callback failed on line " << line_;
109 }
110
111 private:
112 std::string GetJson(Value* value) {
113 std::string json;
114 base::JSONWriter::Write(value, true, &json);
115 return json;
116 }
117
118 DictionaryValue* expected_;
119 int line_;
120 bool called_;
121 };
122
123 } // namespace
124
125 class ExtensionSettingsSyncUnittest : public testing::Test {
126 public:
127 virtual void SetUp() {
128 ui_message_loop_.reset(new MessageLoopForUI());
129 // Use the same message loop for the UI and FILE threads, giving a test
130 // pattern where storage API calls get posted to the same message loop (the
131 // current one), then all run with MessageLoop::current()->RunAllPending().
132 ui_thread_.reset(
133 new BrowserThread(BrowserThread::UI, MessageLoop::current()));
134 file_thread_.reset(
135 new BrowserThread(BrowserThread::FILE, MessageLoop::current()));
136 sync_.reset(new MockSyncChangeProcessor());
137
138 FilePath temp_dir;
139 file_util::CreateNewTempDirectory(FilePath::StringType(), &temp_dir);
140 settings_ = new ExtensionSettings(temp_dir);
141 }
142
143 protected:
144 void GetStorage(
145 const std::string& extension_id,
146 SyncableExtensionSettingsStorage** storage) {
147 settings_->GetStorage(
148 extension_id,
149 base::Bind(
150 &ExtensionSettingsSyncUnittest::AssignStorage,
151 base::Unretained(this),
152 storage));
153 MessageLoop::current()->RunAllPending();
154 }
155
156 scoped_ptr<MockSyncChangeProcessor> sync_;
157 scoped_refptr<ExtensionSettings> settings_;
158
159 private:
160 void AssignStorage(
161 SyncableExtensionSettingsStorage** assign_to,
162 SyncableExtensionSettingsStorage* storage) {
163 DCHECK(storage != NULL);
164 *assign_to = storage;
165 }
166
167 scoped_ptr<MessageLoopForUI> ui_message_loop_;
168 scoped_ptr<BrowserThread> ui_thread_;
169 scoped_ptr<BrowserThread> file_thread_;
170 };
171
172 TEST_F(ExtensionSettingsSyncUnittest, NoDataDoesNotInvokeSync) {
173 SyncableExtensionSettingsStorage* storage1;
174 SyncableExtensionSettingsStorage* storage2;
175 DictionaryValue empty_dict;
176
177 // Have one extension created before sync is set up, the other created after.
178 GetStorage("storage1", &storage1);
179 settings_->MergeDataAndStartSyncing(
180 syncable::EXTENSION_SETTINGS,
181 SyncDataList(),
182 sync_.get());
183 MessageLoop::current()->RunAllPending();
184 GetStorage("storage2", &storage2);
185
186 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
187 MessageLoop::current()->RunAllPending();
188
189 ASSERT_EQ(0u, sync_->changes().size());
190 }
191
192 TEST_F(ExtensionSettingsSyncUnittest, InSyncDataDoesNotInvokeSync) {
193 StringValue value1("fooValue");
194 ListValue value2;
195 value2.Append(StringValue::CreateStringValue("barValue"));
196
197 SyncableExtensionSettingsStorage* storage1;
198 SyncableExtensionSettingsStorage* storage2;
199
200 GetStorage("storage1", &storage1);
201 GetStorage("storage2", &storage2);
202
203 storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback());
204 storage2->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback());
205 MessageLoop::current()->RunAllPending();
206
207 SyncDataList sync_data;
208 sync_data.push_back(ExtensionSettingsSyncHelper::CreateData(
209 "storage1", "foo", value1));
210 sync_data.push_back(ExtensionSettingsSyncHelper::CreateData(
211 "storage2", "bar", value2));
212
213 settings_->MergeDataAndStartSyncing(
214 syncable::EXTENSION_SETTINGS, sync_data, sync_.get());
215 MessageLoop::current()->RunAllPending();
216 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
217 MessageLoop::current()->RunAllPending();
218
219 // Already in sync, so no changes.
220 ASSERT_EQ(0u, sync_->changes().size());
221 }
222
223 TEST_F(ExtensionSettingsSyncUnittest, LocalDataWithNoSyncDataIsPushedToSync) {
224 StringValue value1("fooValue");
225 ListValue value2;
226 value2.Append(StringValue::CreateStringValue("barValue"));
227
228 SyncableExtensionSettingsStorage* storage1;
229 SyncableExtensionSettingsStorage* storage2;
230
231 GetStorage("storage1", &storage1);
232 GetStorage("storage2", &storage2);
233
234 storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback());
235 storage2->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback());
236 MessageLoop::current()->RunAllPending();
237
238 settings_->MergeDataAndStartSyncing(
239 syncable::EXTENSION_SETTINGS, SyncDataList(), sync_.get());
240 MessageLoop::current()->RunAllPending();
241
242 // All settings should have been pushed to sync.
243 ASSERT_EQ(2u, sync_->changes().size());
244 ExtensionSettingsSyncData change = sync_->GetOnlyChange("storage1", "foo");
245 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
246 ASSERT_TRUE(value1.Equals(change.value()));
247 change = sync_->GetOnlyChange("storage2", "bar");
248 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
249 ASSERT_TRUE(value2.Equals(change.value()));
250
251 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
252 MessageLoop::current()->RunAllPending();
253 }
254
255 TEST_F(ExtensionSettingsSyncUnittest, AnySyncDataOverwritesLocalData) {
256 StringValue value1("fooValue");
257 ListValue value2;
258 value2.Append(StringValue::CreateStringValue("barValue"));
259
260 SyncableExtensionSettingsStorage* storage1;
261 SyncableExtensionSettingsStorage* storage2;
262
263 // Pre-populate one of the storage areas.
264 GetStorage("storage1", &storage1);
265 storage1->Set(
266 "overwriteMe", value1, new ExtensionSettingsStorage::NoopCallback());
267 MessageLoop::current()->RunAllPending();
268
269 SyncDataList sync_data;
270 sync_data.push_back(ExtensionSettingsSyncHelper::CreateData(
271 "storage1", "foo", value1));
272 sync_data.push_back(ExtensionSettingsSyncHelper::CreateData(
273 "storage2", "bar", value2));
274 settings_->MergeDataAndStartSyncing(
275 syncable::EXTENSION_SETTINGS, sync_data, sync_.get());
276 MessageLoop::current()->RunAllPending();
277
278 GetStorage("storage2", &storage2);
279
280 // All changes should be local, so no sync changes.
281 ASSERT_EQ(0u, sync_->changes().size());
282
283 // Sync settings should have been pushed to local settings.
284 DictionaryValue settings1;
285 settings1.Set("foo", value1.DeepCopy());
286 DictionaryValue settings2;
287 settings2.Set("bar", value2.DeepCopy());
288 storage1->Get(NEW_CALLBACK(&settings1));
289 storage2->Get(NEW_CALLBACK(&settings2));
290 MessageLoop::current()->RunAllPending();
291
292 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
293 MessageLoop::current()->RunAllPending();
294 }
295
296 TEST_F(ExtensionSettingsSyncUnittest, ProcessSyncChanges) {
297 StringValue value1("fooValue");
298 ListValue value2;
299 value2.Append(StringValue::CreateStringValue("barValue"));
300
301 SyncableExtensionSettingsStorage* storage1;
302 SyncableExtensionSettingsStorage* storage2;
303 // Maintain dictionaries mirrored to the expected values of the settings in
304 // each storage area.
305 // TODO rename these.
306 DictionaryValue settings1, settings2;
307
308 // Make storage1 initialised from local data, storage2 initialised from sync.
309 GetStorage("storage1", &storage1);
310 GetStorage("storage2", &storage2);
311
312 storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback());
313 settings1.Set("foo", value1.DeepCopy());
314 MessageLoop::current()->RunAllPending();
315
316 SyncDataList sync_data;
317 sync_data.push_back(ExtensionSettingsSyncHelper::CreateData(
318 "storage2", "bar", value2));
319 settings2.Set("bar", value2.DeepCopy());
320
321 settings_->MergeDataAndStartSyncing(
322 syncable::EXTENSION_SETTINGS, sync_data, sync_.get());
323 MessageLoop::current()->RunAllPending();
324
325 // Make sync add some settings.
326 SyncChangeList change_list;
327 change_list.push_back(ExtensionSettingsSyncHelper::CreateAdd(
328 "storage1", "bar", value2));
329 settings1.Set("bar", value2.DeepCopy());
330 change_list.push_back(ExtensionSettingsSyncHelper::CreateAdd(
331 "storage2", "foo", value1));
332 settings2.Set("foo", value1.DeepCopy());
333 settings_->ProcessSyncChanges(FROM_HERE, change_list);
334 MessageLoop::current()->RunAllPending();
335
336 storage1->Get(NEW_CALLBACK(&settings1));
337 storage2->Get(NEW_CALLBACK(&settings2));
338 MessageLoop::current()->RunAllPending();
339
340 // Make sync update some settings, storage1 the new setting, storage2 the
341 // initial setting.
342 change_list.clear();
343 change_list.push_back(ExtensionSettingsSyncHelper::CreateUpdate(
344 "storage1", "bar", value2));
345 settings1.Set("bar", value2.DeepCopy());
346 change_list.push_back(ExtensionSettingsSyncHelper::CreateUpdate(
347 "storage2", "bar", value1));
348 settings2.Set("bar", value1.DeepCopy());
349 settings_->ProcessSyncChanges(FROM_HERE, change_list);
350 MessageLoop::current()->RunAllPending();
351
352 storage1->Get(NEW_CALLBACK(&settings1));
353 storage2->Get(NEW_CALLBACK(&settings2));
354 MessageLoop::current()->RunAllPending();
355
356 // Make sync remove some settings, storage1 the initial setting, storage2 the
357 // new setting.
358 change_list.clear();
359 change_list.push_back(ExtensionSettingsSyncHelper::CreateDelete(
360 "storage1", "foo"));
361 settings1.Remove("foo", NULL);
362 change_list.push_back(ExtensionSettingsSyncHelper::CreateDelete(
363 "storage2", "foo"));
364 settings2.Remove("foo", NULL);
365 settings_->ProcessSyncChanges(FROM_HERE, change_list);
366 MessageLoop::current()->RunAllPending();
367
368 storage1->Get(NEW_CALLBACK(&settings1));
369 storage2->Get(NEW_CALLBACK(&settings2));
370 MessageLoop::current()->RunAllPending();
371
372 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
373 MessageLoop::current()->RunAllPending();
374 }
375
376 TEST_F(ExtensionSettingsSyncUnittest, PushToSync) {
377 StringValue value1("fooValue");
378 ListValue value2;
379 value2.Append(StringValue::CreateStringValue("barValue"));
380
381 SyncableExtensionSettingsStorage* storage1;
382 SyncableExtensionSettingsStorage* storage2;
383 SyncableExtensionSettingsStorage* storage3;
384 SyncableExtensionSettingsStorage* storage4;
385
386 // Make storage1/2 initialised from local data, storage3/4 initialised from
387 // sync.
388 GetStorage("storage1", &storage1);
389 GetStorage("storage2", &storage2);
390 GetStorage("storage3", &storage3);
391 GetStorage("storage4", &storage4);
392
393 storage1->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback());
394 storage2->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback());
395 MessageLoop::current()->RunAllPending();
396
397 SyncDataList sync_data;
398 sync_data.push_back(ExtensionSettingsSyncHelper::CreateData(
399 "storage3", "bar", value2));
400 sync_data.push_back(ExtensionSettingsSyncHelper::CreateData(
401 "storage4", "bar", value2));
402
403 settings_->MergeDataAndStartSyncing(
404 syncable::EXTENSION_SETTINGS, sync_data, sync_.get());
405 MessageLoop::current()->RunAllPending();
406
407 // Add something locally.
408 storage1->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback());
409 storage2->Set("bar", value2, new ExtensionSettingsStorage::NoopCallback());
410 storage3->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback());
411 storage4->Set("foo", value1, new ExtensionSettingsStorage::NoopCallback());
412 MessageLoop::current()->RunAllPending();
413
414 ExtensionSettingsSyncData change = sync_->GetOnlyChange("storage1", "bar");
415 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
416 ASSERT_TRUE(value2.Equals(change.value()));
417 sync_->GetOnlyChange("storage2", "bar");
418 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
419 ASSERT_TRUE(value2.Equals(change.value()));
420 change = sync_->GetOnlyChange("storage3", "foo");
421 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
422 ASSERT_TRUE(value1.Equals(change.value()));
423 change = sync_->GetOnlyChange("storage4", "foo");
424 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
425 ASSERT_TRUE(value1.Equals(change.value()));
426
427 // Change something locally, storage1/3 the new setting and storage2/4 the
428 // initial setting, for all combinations of local vs sync intialisation and
429 // new vs initial.
430 sync_->ClearChanges();
431 storage1->Set("bar", value1, new ExtensionSettingsStorage::NoopCallback());
432 storage2->Set("foo", value2, new ExtensionSettingsStorage::NoopCallback());
433 storage3->Set("bar", value1, new ExtensionSettingsStorage::NoopCallback());
434 storage4->Set("foo", value2, new ExtensionSettingsStorage::NoopCallback());
435 MessageLoop::current()->RunAllPending();
436
437 change = sync_->GetOnlyChange("storage1", "bar");
438 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
439 ASSERT_TRUE(value1.Equals(change.value()));
440 change = sync_->GetOnlyChange("storage2", "foo");
441 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
442 ASSERT_TRUE(value2.Equals(change.value()));
443 change = sync_->GetOnlyChange("storage3", "bar");
444 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
445 ASSERT_TRUE(value1.Equals(change.value()));
446 change = sync_->GetOnlyChange("storage4", "foo");
447 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
448 ASSERT_TRUE(value2.Equals(change.value()));
449
450 // Remove something locally, storage1/3 the new setting and storage2/4 the
451 // initial setting, for all combinations of local vs sync intialisation and
452 // new vs initial.
453 sync_->ClearChanges();
454 storage1->Remove("foo", new ExtensionSettingsStorage::NoopCallback());
455 storage2->Remove("bar", new ExtensionSettingsStorage::NoopCallback());
456 storage3->Remove("foo", new ExtensionSettingsStorage::NoopCallback());
457 storage4->Remove("bar", new ExtensionSettingsStorage::NoopCallback());
458 MessageLoop::current()->RunAllPending();
459
460 change = sync_->GetOnlyChange("storage1", "foo");
461 ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type());
462 change = sync_->GetOnlyChange("storage2", "bar");
463 ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type());
464 change = sync_->GetOnlyChange("storage3", "foo");
465 ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type());
466 change = sync_->GetOnlyChange("storage4", "bar");
467 ASSERT_EQ(SyncChange::ACTION_DELETE, change.change_type());
468
469 // XXX CLEAR
470
471 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
472 MessageLoop::current()->RunAllPending();
473 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698