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

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

Issue 7775008: Enable sync for the settings from the Extension Settings API. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Review #2 against correct branch Created 9 years, 3 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/scoped_ptr.h"
12 #include "base/message_loop.h"
13 #include "base/task.h"
14 #include "chrome/browser/extensions/extension_settings.h"
15 #include "chrome/browser/extensions/extension_settings_storage_cache.h"
16 #include "chrome/browser/extensions/extension_settings_noop_storage.h"
17 #include "chrome/browser/extensions/extension_settings_sync_util.h"
18 #include "chrome/browser/extensions/syncable_extension_settings_storage.h"
19 #include "chrome/browser/extensions/test_extension_service.h"
20 #include "chrome/browser/sync/api/sync_change_processor.h"
21 #include "content/browser/browser_thread.h"
22
23 // TODO(kalman): Integration tests for sync.
24
25 namespace {
26
27 // Gets the pretty-printed JSON for a value.
28 static std::string GetJson(const Value& value) {
29 std::string json;
30 base::JSONWriter::Write(&value, true, &json);
31 return json;
32 }
33
34 // Returns whether two Values are equal.
35 testing::AssertionResult ValuesEq(
36 const char* expected_expr,
37 const char* actual_expr,
38 const Value* expected,
39 const Value* actual) {
40 if (expected == actual) {
41 return testing::AssertionSuccess();
42 }
43 if (!expected && actual) {
44 return testing::AssertionFailure() <<
45 "Expected NULL, actual: " << GetJson(*actual);
46 }
47 if (expected && !actual) {
48 return testing::AssertionFailure() <<
49 "Expected: " << GetJson(*expected) << ", actual NULL";
50 }
51 if (!expected->Equals(actual)) {
52 return testing::AssertionFailure() <<
53 "Expected: " << GetJson(*expected) << ", actual: " << GetJson(*actual);
54 }
55 return testing::AssertionSuccess();
56 }
57
58 // Returns whether the result of a storage operation is an expected value.
59 // Logs when different.
60 testing::AssertionResult SettingsEq(
61 const char* expected_expr,
62 const char* actual_expr,
63 const DictionaryValue* expected,
64 const ExtensionSettingsStorage::Result actual) {
65 if (actual.HasError()) {
66 return testing::AssertionFailure() <<
67 "Expected: " << GetJson(*expected) <<
68 ", actual has error: " << actual.GetError();
69 }
70 return ValuesEq(
71 expected_expr, actual_expr, expected, actual.GetSettings());
72 }
73
74 // SyncChangeProcessor which just records the changes made, accessed after
75 // being converted to the more useful ExtensionSettingSyncData via changes().
76 class MockSyncChangeProcessor : public SyncChangeProcessor {
77 public:
78 virtual SyncError ProcessSyncChanges(
79 const tracked_objects::Location& from_here,
80 const SyncChangeList& change_list) OVERRIDE {
81 for (SyncChangeList::const_iterator it = change_list.begin();
82 it != change_list.end(); ++it) {
83 changes_.push_back(ExtensionSettingSyncData(*it));
84 }
85 return SyncError();
86 }
87
88 const ExtensionSettingSyncDataList& changes() { return changes_; }
89
90 void ClearChanges() {
91 changes_.clear();
92 }
93
94 // Returns the only change for a given extension setting. If there is not
95 // exactly 1 change for that key, a test assertion will fail.
96 ExtensionSettingSyncData GetOnlyChange(
97 const std::string& extension_id, const std::string& key) {
98 ExtensionSettingSyncDataList matching_changes;
99 for (ExtensionSettingSyncDataList::iterator it = changes_.begin();
100 it != changes_.end(); ++it) {
101 if (it->extension_id() == extension_id && it->key() == key) {
102 matching_changes.push_back(*it);
103 }
104 }
105 if (matching_changes.empty()) {
106 ADD_FAILURE() << "No matching changes for " << extension_id << "/" <<
107 key << " (out of " << changes_.size() << ")";
108 return ExtensionSettingSyncData(SyncChange::ACTION_INVALID, "", "", NULL);
109 }
110 if (matching_changes.size() != 1u) {
111 ADD_FAILURE() << matching_changes.size() << " matching changes for " <<
112 extension_id << "/" << key << " (out of " << changes_.size() << ")";
113 }
114 return matching_changes[0];
115 }
116
117 private:
118 ExtensionSettingSyncDataList changes_;
119 };
120
121 // Fake ExtensionService which just allows Extensions with a specific id to be
122 // added to it and returned.
123 class FakeExtensionService : public TestExtensionService {
124 public:
125 explicit FakeExtensionService(const FilePath& file_path)
126 : file_path_(file_path) {}
127
128 virtual const std::vector<std::string> GetAllExtensionIds() const OVERRIDE {
129 return extension_ids_;
130 }
131
132 // Adds an extension to those that will be returned from extensions().
133 void AddExtension(const std::string& extension_id) {
134 extension_ids_.push_back(extension_id);
135 }
136
137 private:
138 FilePath file_path_;
139 std::vector<std::string> extension_ids_;
140 };
141
142 } // namespace
143
144 class ExtensionSettingsSyncUnittest : public testing::Test {
145 public:
146 ExtensionSettingsSyncUnittest()
147 : ui_thread_(BrowserThread::UI, MessageLoop::current()),
148 file_thread_(BrowserThread::FILE, MessageLoop::current()) {}
149
150 virtual void SetUp() {
151 FilePath temp_dir;
152 file_util::CreateNewTempDirectory(FilePath::StringType(), &temp_dir);
153 settings_ = new ExtensionSettings(temp_dir);
154 service_.reset(new FakeExtensionService(temp_dir));
155 settings_->SetExtensionService(service_.get());
156 }
157
158 protected:
159 // Creates a new extension storage object and adds a record of the extension
160 // to the extension service.
161 SyncableExtensionSettingsStorage* GetStorage(
162 const std::string& extension_id) {
163 bool have_extension = false;
164 std::vector<std::string> extension_ids(service_->GetAllExtensionIds());
165 for (std::vector<std::string>::iterator it = extension_ids.begin();
166 it != extension_ids.end(); ++it) {
167 if (*it == extension_id) {
168 have_extension = true;
169 break;
170 }
171 }
172 if (!have_extension) {
173 service_->AddExtension(extension_id);
174 }
175 return static_cast<SyncableExtensionSettingsStorage*>(
176 settings_->GetStorage(extension_id));
177 }
178
179 MockSyncChangeProcessor sync_;
180 scoped_ptr<FakeExtensionService> service_;
181 scoped_refptr<ExtensionSettings> settings_;
182
183 // Gets all the sync data from settings_ as a map from extension id to its
184 // sync data.
185 std::map<std::string, ExtensionSettingSyncDataList> GetAllSyncData() {
186 SyncDataList as_list =
187 settings_->GetAllSyncData(syncable::EXTENSION_SETTINGS);
188 std::map<std::string, ExtensionSettingSyncDataList> as_map;
189 for (SyncDataList::iterator it = as_list.begin();
190 it != as_list.end(); ++it) {
191 ExtensionSettingSyncData sync_data(*it);
192 as_map[sync_data.extension_id()].push_back(sync_data);
193 }
194 return as_map;
195 }
196
197 private:
198 // Need these so that the DCHECKs for running on FILE or UI threads pass.
199 MessageLoopForUI ui_message_loop_;
200 BrowserThread ui_thread_;
201 BrowserThread file_thread_;
202 };
203
204 TEST_F(ExtensionSettingsSyncUnittest, NoDataDoesNotInvokeSync) {
205 ASSERT_EQ(0u, GetAllSyncData().size());
206
207 // Have one extension created before sync is set up, the other created after.
208 GetStorage("s1");
209 ASSERT_EQ(0u, GetAllSyncData().size());
210
211 settings_->MergeDataAndStartSyncing(
212 syncable::EXTENSION_SETTINGS,
213 SyncDataList(),
214 &sync_);
215
216 GetStorage("s2");
217 ASSERT_EQ(0u, GetAllSyncData().size());
218
219 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
220
221 ASSERT_EQ(0u, sync_.changes().size());
222 ASSERT_EQ(0u, GetAllSyncData().size());
223 }
224
225 TEST_F(ExtensionSettingsSyncUnittest, InSyncDataDoesNotInvokeSync) {
226 StringValue value1("fooValue");
227 ListValue value2;
228 value2.Append(StringValue::CreateStringValue("barValue"));
229
230 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
231 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
232
233 storage1->Set("foo", value1);
234 storage2->Set("bar", value2);
235
236 std::map<std::string, ExtensionSettingSyncDataList> all_sync_data =
237 GetAllSyncData();
238 ASSERT_EQ(2u, all_sync_data.size());
239 ASSERT_EQ(1u, all_sync_data["s1"].size());
240 ASSERT_PRED_FORMAT2(ValuesEq, &value1, &all_sync_data["s1"][0].value());
241 ASSERT_EQ(1u, all_sync_data["s2"].size());
242 ASSERT_PRED_FORMAT2(ValuesEq, &value2, &all_sync_data["s2"][0].value());
243
244 SyncDataList sync_data;
245 sync_data.push_back(extension_settings_sync_util::CreateData(
246 "s1", "foo", value1));
247 sync_data.push_back(extension_settings_sync_util::CreateData(
248 "s2", "bar", value2));
249
250 settings_->MergeDataAndStartSyncing(
251 syncable::EXTENSION_SETTINGS, sync_data, &sync_);
252 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
253
254 // Already in sync, so no changes.
255 ASSERT_EQ(0u, sync_.changes().size());
256 }
257
258 TEST_F(ExtensionSettingsSyncUnittest, LocalDataWithNoSyncDataIsPushedToSync) {
259 StringValue value1("fooValue");
260 ListValue value2;
261 value2.Append(StringValue::CreateStringValue("barValue"));
262
263 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
264 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
265
266 storage1->Set("foo", value1);
267 storage2->Set("bar", value2);
268
269 settings_->MergeDataAndStartSyncing(
270 syncable::EXTENSION_SETTINGS, SyncDataList(), &sync_);
271
272 // All settings should have been pushed to sync.
273 ASSERT_EQ(2u, sync_.changes().size());
274 ExtensionSettingSyncData change = sync_.GetOnlyChange("s1", "foo");
275 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
276 ASSERT_TRUE(value1.Equals(&change.value()));
277 change = sync_.GetOnlyChange("s2", "bar");
278 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
279 ASSERT_TRUE(value2.Equals(&change.value()));
280
281 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
282 }
283
284 TEST_F(ExtensionSettingsSyncUnittest, AnySyncDataOverwritesLocalData) {
285 StringValue value1("fooValue");
286 ListValue value2;
287 value2.Append(StringValue::CreateStringValue("barValue"));
288
289 // Maintain dictionaries mirrored to the expected values of the settings in
290 // each storage area.
291 DictionaryValue expected1, expected2;
292
293 // Pre-populate one of the storage areas.
294 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
295 storage1->Set("overwriteMe", value1);
296
297 SyncDataList sync_data;
298 sync_data.push_back(extension_settings_sync_util::CreateData(
299 "s1", "foo", value1));
300 sync_data.push_back(extension_settings_sync_util::CreateData(
301 "s2", "bar", value2));
302 settings_->MergeDataAndStartSyncing(
303 syncable::EXTENSION_SETTINGS, sync_data, &sync_);
304 expected1.Set("foo", value1.DeepCopy());
305 expected2.Set("bar", value2.DeepCopy());
306
307 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
308
309 // All changes should be local, so no sync changes.
310 ASSERT_EQ(0u, sync_.changes().size());
311
312 // Sync settings should have been pushed to local settings.
313 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get());
314 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get());
315
316 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
317 }
318
319 TEST_F(ExtensionSettingsSyncUnittest, ProcessSyncChanges) {
320 StringValue value1("fooValue");
321 ListValue value2;
322 value2.Append(StringValue::CreateStringValue("barValue"));
323
324 // Maintain dictionaries mirrored to the expected values of the settings in
325 // each storage area.
326 DictionaryValue expected1, expected2;
327
328 // Make storage1 initialised from local data, storage2 initialised from sync.
329 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
330 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
331
332 storage1->Set("foo", value1);
333 expected1.Set("foo", value1.DeepCopy());
334
335 SyncDataList sync_data;
336 sync_data.push_back(extension_settings_sync_util::CreateData(
337 "s2", "bar", value2));
338
339 settings_->MergeDataAndStartSyncing(
340 syncable::EXTENSION_SETTINGS, sync_data, &sync_);
341 expected2.Set("bar", value2.DeepCopy());
342
343 // Make sync add some settings.
344 SyncChangeList change_list;
345 change_list.push_back(extension_settings_sync_util::CreateAdd(
346 "s1", "bar", value2));
347 change_list.push_back(extension_settings_sync_util::CreateAdd(
348 "s2", "foo", value1));
349 settings_->ProcessSyncChanges(FROM_HERE, change_list);
350 expected1.Set("bar", value2.DeepCopy());
351 expected2.Set("foo", value1.DeepCopy());
352
353 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get());
354 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get());
355
356 // Make sync update some settings, storage1 the new setting, storage2 the
357 // initial setting.
358 change_list.clear();
359 change_list.push_back(extension_settings_sync_util::CreateUpdate(
360 "s1", "bar", value2));
361 change_list.push_back(extension_settings_sync_util::CreateUpdate(
362 "s2", "bar", value1));
363 settings_->ProcessSyncChanges(FROM_HERE, change_list);
364 expected1.Set("bar", value2.DeepCopy());
365 expected2.Set("bar", value1.DeepCopy());
366
367 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get());
368 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get());
369
370 // Make sync remove some settings, storage1 the initial setting, storage2 the
371 // new setting.
372 change_list.clear();
373 change_list.push_back(extension_settings_sync_util::CreateDelete(
374 "s1", "foo"));
375 change_list.push_back(extension_settings_sync_util::CreateDelete(
376 "s2", "foo"));
377 settings_->ProcessSyncChanges(FROM_HERE, change_list);
378 expected1.Remove("foo", NULL);
379 expected2.Remove("foo", NULL);
380
381 ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get());
382 ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get());
383
384 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
385 }
386
387 TEST_F(ExtensionSettingsSyncUnittest, PushToSync) {
388 StringValue value1("fooValue");
389 ListValue value2;
390 value2.Append(StringValue::CreateStringValue("barValue"));
391
392 // Make storage1/2 initialised from local data, storage3/4 initialised from
393 // sync.
394 SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
395 SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
396 SyncableExtensionSettingsStorage* storage3 = GetStorage("s3");
397 SyncableExtensionSettingsStorage* storage4 = GetStorage("s4");
398
399 storage1->Set("foo", value1);
400 storage2->Set("foo", value1);
401
402 SyncDataList sync_data;
403 sync_data.push_back(extension_settings_sync_util::CreateData(
404 "s3", "bar", value2));
405 sync_data.push_back(extension_settings_sync_util::CreateData(
406 "s4", "bar", value2));
407
408 settings_->MergeDataAndStartSyncing(
409 syncable::EXTENSION_SETTINGS, sync_data, &sync_);
410
411 // Add something locally.
412 storage1->Set("bar", value2);
413 storage2->Set("bar", value2);
414 storage3->Set("foo", value1);
415 storage4->Set("foo", value1);
416
417 ExtensionSettingSyncData change = sync_.GetOnlyChange("s1", "bar");
418 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
419 ASSERT_TRUE(value2.Equals(&change.value()));
420 sync_.GetOnlyChange("s2", "bar");
421 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
422 ASSERT_TRUE(value2.Equals(&change.value()));
423 change = sync_.GetOnlyChange("s3", "foo");
424 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
425 ASSERT_TRUE(value1.Equals(&change.value()));
426 change = sync_.GetOnlyChange("s4", "foo");
427 ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
428 ASSERT_TRUE(value1.Equals(&change.value()));
429
430 // Change something locally, storage1/3 the new setting and storage2/4 the
431 // initial setting, for all combinations of local vs sync intialisation and
432 // new vs initial.
433 sync_.ClearChanges();
434 storage1->Set("bar", value1);
435 storage2->Set("foo", value2);
436 storage3->Set("bar", value1);
437 storage4->Set("foo", value2);
438
439 change = sync_.GetOnlyChange("s1", "bar");
440 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
441 ASSERT_TRUE(value1.Equals(&change.value()));
442 change = sync_.GetOnlyChange("s2", "foo");
443 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
444 ASSERT_TRUE(value2.Equals(&change.value()));
445 change = sync_.GetOnlyChange("s3", "bar");
446 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
447 ASSERT_TRUE(value1.Equals(&change.value()));
448 change = sync_.GetOnlyChange("s4", "foo");
449 ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
450 ASSERT_TRUE(value2.Equals(&change.value()));
451
452 // Remove something locally, storage1/3 the new setting and storage2/4 the
453 // initial setting, for all combinations of local vs sync intialisation and
454 // new vs initial.
455 sync_.ClearChanges();
456 storage1->Remove("foo");
457 storage2->Remove("bar");
458 storage3->Remove("foo");
459 storage4->Remove("bar");
460
461 ASSERT_EQ(
462 SyncChange::ACTION_DELETE,
463 sync_.GetOnlyChange("s1", "foo").change_type());
464 ASSERT_EQ(
465 SyncChange::ACTION_DELETE,
466 sync_.GetOnlyChange("s2", "bar").change_type());
467 ASSERT_EQ(
468 SyncChange::ACTION_DELETE,
469 sync_.GetOnlyChange("s3", "foo").change_type());
470 ASSERT_EQ(
471 SyncChange::ACTION_DELETE,
472 sync_.GetOnlyChange("s4", "bar").change_type());
473
474 // Remove some nonexistent settings.
475 sync_.ClearChanges();
476 storage1->Remove("foo");
477 storage2->Remove("bar");
478 storage3->Remove("foo");
479 storage4->Remove("bar");
480
481 ASSERT_EQ(0u, sync_.changes().size());
482
483 // Clear the rest of the settings. Add the removed ones back first so that
484 // more than one setting is cleared.
485 storage1->Set("foo", value1);
486 storage2->Set("bar", value2);
487 storage3->Set("foo", value1);
488 storage4->Set("bar", value2);
489
490 sync_.ClearChanges();
491 storage1->Clear();
492 storage2->Clear();
493 storage3->Clear();
494 storage4->Clear();
495
496 ASSERT_EQ(
497 SyncChange::ACTION_DELETE,
498 sync_.GetOnlyChange("s1", "foo").change_type());
499 ASSERT_EQ(
500 SyncChange::ACTION_DELETE,
501 sync_.GetOnlyChange("s1", "bar").change_type());
502 ASSERT_EQ(
503 SyncChange::ACTION_DELETE,
504 sync_.GetOnlyChange("s2", "foo").change_type());
505 ASSERT_EQ(
506 SyncChange::ACTION_DELETE,
507 sync_.GetOnlyChange("s2", "bar").change_type());
508 ASSERT_EQ(
509 SyncChange::ACTION_DELETE,
510 sync_.GetOnlyChange("s3", "foo").change_type());
511 ASSERT_EQ(
512 SyncChange::ACTION_DELETE,
513 sync_.GetOnlyChange("s3", "bar").change_type());
514 ASSERT_EQ(
515 SyncChange::ACTION_DELETE,
516 sync_.GetOnlyChange("s4", "foo").change_type());
517 ASSERT_EQ(
518 SyncChange::ACTION_DELETE,
519 sync_.GetOnlyChange("s4", "bar").change_type());
520
521 settings_->StopSyncing(syncable::EXTENSION_SETTINGS);
522 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698