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

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

Powered by Google App Engine
This is Rietveld 408576698