diff options
author | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-16 09:37:10 +0000 |
---|---|---|
committer | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-16 09:37:10 +0000 |
commit | deb16806c9991b694052b4a6a34336bb261ccda3 (patch) | |
tree | e2b37f2afe9336f3724da7671d5254d0288f056d /chrome/browser/sync | |
parent | b426e737a866aa08b258cc45d8bb7355fd284644 (diff) | |
download | chromium_src-deb16806c9991b694052b4a6a34336bb261ccda3.zip chromium_src-deb16806c9991b694052b4a6a34336bb261ccda3.tar.gz chromium_src-deb16806c9991b694052b4a6a34336bb261ccda3.tar.bz2 |
Add sync integration tests for extension settings.
R=akalin@chromium.org
BUG=
TEST=sync_integrations_tests --gtest_filter=TwoClientExtensionSettingsSyncTest.*
Review URL: http://codereview.chromium.org/9347014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122256 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/sync')
9 files changed, 344 insertions, 15 deletions
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc index cdbbef6..d9501f5 100644 --- a/chrome/browser/sync/test/integration/apps_helper.cc +++ b/chrome/browser/sync/test/integration/apps_helper.cc @@ -40,7 +40,7 @@ bool AllProfilesHaveSameAppsAsVerifier() { return true; } -void InstallApp(Profile* profile, int index) { +std::string InstallApp(Profile* profile, int index) { return SyncExtensionHelper::GetInstance()->InstallExtension( profile, CreateFakeAppName(index), Extension::TYPE_HOSTED_APP); } diff --git a/chrome/browser/sync/test/integration/apps_helper.h b/chrome/browser/sync/test/integration/apps_helper.h index b080866..c7faae0 100644 --- a/chrome/browser/sync/test/integration/apps_helper.h +++ b/chrome/browser/sync/test/integration/apps_helper.h @@ -22,8 +22,9 @@ bool HasSameAppsAsVerifier(int index) WARN_UNUSED_RESULT; // Returns true iff all existing profiles have the same apps as the verifier. bool AllProfilesHaveSameAppsAsVerifier() WARN_UNUSED_RESULT; -// Installs the app for the given index to |profile|. -void InstallApp(Profile* profile, int index); +// Installs the app for the given index to |profile|, and returns the extension +// ID of the new app. +std::string InstallApp(Profile* profile, int index); // Uninstalls the app for the given index from |profile|. Assumes that it was // previously installed. diff --git a/chrome/browser/sync/test/integration/extension_settings_helper.cc b/chrome/browser/sync/test/integration/extension_settings_helper.cc new file mode 100644 index 0000000..b1a0a8b --- /dev/null +++ b/chrome/browser/sync/test/integration/extension_settings_helper.cc @@ -0,0 +1,119 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/test/integration/extension_settings_helper.h" + +#include "base/bind.h" +#include "base/json/json_writer.h" +#include "base/memory/scoped_ptr.h" +#include "base/logging.h" +#include "base/synchronization/waitable_event.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/settings/settings_frontend.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/integration/extensions_helper.h" +#include "chrome/browser/sync/test/integration/sync_datatype_helper.h" +#include "chrome/browser/sync/test/integration/sync_extension_helper.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_set.h" + +using content::BrowserThread; +using extensions::SettingsStorage; +using sync_datatype_helper::test; + +namespace extension_settings_helper { + +namespace { + +std::string ToJson(const Value& value) { + std::string json; + base::JSONWriter::Write(&value, true /* pretty print */, &json); + return json; +} + +void GetAllSettingsOnFileThread( + scoped_ptr<DictionaryValue>* out, + base::WaitableEvent* signal, + SettingsStorage* storage) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + out->reset(storage->Get().settings().DeepCopy()); + signal->Signal(); +} + +scoped_ptr<DictionaryValue> GetAllSettings( + Profile* profile, const std::string& id) { + base::WaitableEvent signal(false, false); + scoped_ptr<DictionaryValue> settings; + profile->GetExtensionService()->settings_frontend()->RunWithStorage( + id, + extensions::settings_namespace::SYNC, + base::Bind(&GetAllSettingsOnFileThread, &settings, &signal)); + signal.Wait(); + return settings.Pass(); +} + +bool AreSettingsSame(Profile* expected_profile, Profile* actual_profile) { + const ExtensionSet* extensions = + expected_profile->GetExtensionService()->extensions(); + if (extensions->size() != + actual_profile->GetExtensionService()->extensions()->size()) { + ADD_FAILURE(); + return false; + } + + bool same = true; + for (ExtensionSet::const_iterator it = extensions->begin(); + it != extensions->end(); ++it) { + const std::string& id = (*it)->id(); + scoped_ptr<DictionaryValue> expected(GetAllSettings(expected_profile, id)); + scoped_ptr<DictionaryValue> actual(GetAllSettings(actual_profile, id)); + if (!expected->Equals(actual.get())) { + ADD_FAILURE() << + "Expected " << ToJson(*expected) << " got " << ToJson(*actual); + same = false; + } + } + return same; +} + +void SetSettingsOnFileThread( + const DictionaryValue* settings, + base::WaitableEvent* signal, + SettingsStorage* storage) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + storage->Set(SettingsStorage::DEFAULTS, *settings); + signal->Signal(); +} + +} // namespace + +void SetExtensionSettings( + Profile* profile, const std::string& id, const DictionaryValue& settings) { + base::WaitableEvent signal(false, false); + profile->GetExtensionService()->settings_frontend()->RunWithStorage( + id, + extensions::settings_namespace::SYNC, + base::Bind(&SetSettingsOnFileThread, &settings, &signal)); + signal.Wait(); +} + +void SetExtensionSettingsForAllProfiles( + const std::string& id, const DictionaryValue& settings) { + for (int i = 0; i < test()->num_clients(); ++i) + SetExtensionSettings(test()->GetProfile(i), id, settings); + SetExtensionSettings(test()->verifier(), id, settings); +} + +bool AllExtensionSettingsSameAsVerifier() { + bool all_profiles_same = true; + for (int i = 0; i < test()->num_clients(); ++i) { + // &= so that all profiles are tested; analogous to EXPECT over ASSERT. + all_profiles_same &= + AreSettingsSame(test()->verifier(), test()->GetProfile(i)); + } + return all_profiles_same; +} + +} // namespace extension_settings_helper diff --git a/chrome/browser/sync/test/integration/extension_settings_helper.h b/chrome/browser/sync/test/integration/extension_settings_helper.h new file mode 100644 index 0000000..7e92697 --- /dev/null +++ b/chrome/browser/sync/test/integration/extension_settings_helper.h @@ -0,0 +1,33 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_EXTENSION_SETTINGS_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_INTEGRATION_EXTENSION_SETTINGS_HELPER_H_ +#pragma once + +#include <string> + +class Profile; +namespace base { +class DictionaryValue; +} + +namespace extension_settings_helper { + +// Calls Set() with |settings| for |profile| and the extension with ID |id|. +void SetExtensionSettings( + Profile* profile, + const std::string& id, + const base::DictionaryValue& settings); + +// Calls Set() with |settings| for all profiles the extension with ID |id|. +void SetExtensionSettingsForAllProfiles( + const std::string& id, const base::DictionaryValue& settings); + +// Returns whether the extension settings are the same across all profiles. +bool AllExtensionSettingsSameAsVerifier(); + +} // namespace extension_settings_helper + +#endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_EXTENSION_SETTINGS_HELPER_H_ diff --git a/chrome/browser/sync/test/integration/extensions_helper.cc b/chrome/browser/sync/test/integration/extensions_helper.cc index 6358e88..346610a 100644 --- a/chrome/browser/sync/test/integration/extensions_helper.cc +++ b/chrome/browser/sync/test/integration/extensions_helper.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -49,7 +49,7 @@ bool AllProfilesHaveSameExtensions() { } -void InstallExtension(Profile* profile, int index) { +std::string InstallExtension(Profile* profile, int index) { return SyncExtensionHelper::GetInstance()->InstallExtension( profile, CreateFakeExtensionName(index), Extension::TYPE_EXTENSION); } diff --git a/chrome/browser/sync/test/integration/extensions_helper.h b/chrome/browser/sync/test/integration/extensions_helper.h index 25fe367..20f95d6 100644 --- a/chrome/browser/sync/test/integration/extensions_helper.h +++ b/chrome/browser/sync/test/integration/extensions_helper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -28,8 +28,9 @@ bool AllProfilesHaveSameExtensionsAsVerifier() WARN_UNUSED_RESULT; // Returns true iff all existing profiles have the same extensions. bool AllProfilesHaveSameExtensions() WARN_UNUSED_RESULT; -// Installs the extension for the given index to |profile|. -void InstallExtension(Profile* profile, int index); +// Installs the extension for the given index to |profile|, and returns the +// extension ID of the new extension. +std::string InstallExtension(Profile* profile, int index); // Uninstalls the extension for the given index from |profile|. Assumes that // it was previously installed. diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc index 6eeb49d..39e6298 100644 --- a/chrome/browser/sync/test/integration/sync_extension_helper.cc +++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc @@ -12,6 +12,7 @@ #include "chrome/browser/extensions/pending_extension_info.h" #include "chrome/browser/extensions/pending_extension_manager.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/string_ordinal.h" #include "chrome/browser/sync/test/integration/sync_test.h" @@ -59,13 +60,16 @@ void SyncExtensionHelper::SetupIfNecessary(SyncTest* test) { setup_completed_ = true; } -void SyncExtensionHelper::InstallExtension( +std::string SyncExtensionHelper::InstallExtension( Profile* profile, const std::string& name, Extension::Type type) { scoped_refptr<Extension> extension = GetExtension(profile, name, type); - ASSERT_TRUE(extension.get()) << "Could not get extension " << name - << " (profile = " << profile << ")"; + if (!extension.get()) { + NOTREACHED() << "Could not install extension " << name; + return ""; + } profile->GetExtensionService()->OnExtensionInstalled( extension, extension->UpdatesFromGallery(), StringOrdinal()); + return extension->id(); } void SyncExtensionHelper::UninstallExtension( diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.h b/chrome/browser/sync/test/integration/sync_extension_helper.h index 7968556..1e85afe 100644 --- a/chrome/browser/sync/test/integration/sync_extension_helper.h +++ b/chrome/browser/sync/test/integration/sync_extension_helper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,7 +16,6 @@ #include "base/memory/singleton.h" #include "chrome/common/extensions/extension.h" -class Extension; class Profile; class SyncTest; @@ -32,8 +31,9 @@ class SyncExtensionHelper { // internal data structures. void SetupIfNecessary(SyncTest* test); - // Installs the extension with the given name to |profile|. - void InstallExtension( + // Installs the extension with the given name to |profile|, and returns the + // extension ID of the new extension. + std::string InstallExtension( Profile* profile, const std::string& name, Extension::Type type); // Uninstalls the extension with the given name from |profile|. diff --git a/chrome/browser/sync/test/integration/two_client_extension_settings_sync_test.cc b/chrome/browser/sync/test/integration/two_client_extension_settings_sync_test.cc new file mode 100644 index 0000000..bd581dd --- /dev/null +++ b/chrome/browser/sync/test/integration/two_client_extension_settings_sync_test.cc @@ -0,0 +1,171 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/stringprintf.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/integration/extension_settings_helper.h" +#include "chrome/browser/sync/test/integration/extensions_helper.h" +#include "chrome/browser/sync/test/integration/sync_datatype_helper.h" +#include "chrome/browser/sync/test/integration/sync_test.h" + +namespace { + +using extension_settings_helper::SetExtensionSettings; +using extension_settings_helper::SetExtensionSettingsForAllProfiles; +using extension_settings_helper::AllExtensionSettingsSameAsVerifier; +using extensions_helper::InstallExtension; +using sync_datatype_helper::test; + +std::string InstallExtensionForAllProfiles(int index) { + for (int i = 0; i < test()->num_clients(); ++i) + InstallExtension(test()->GetProfile(i), index); + return InstallExtension(test()->verifier(), index); +} + +// Generic mutations done after the initial setup of all tests. Note that +// unfortuately we can't test existing configurations of the sync server since +// the tests don't support that. +void MutateSomeSettings( + int seed, // used to modify the mutation values, not keys. + const std::string& extension0, + const std::string& extension1, + const std::string& extension2) { + { + // Write to extension0 from profile 0 but not profile 1. + DictionaryValue settings; + settings.SetString("asdf", StringPrintf("asdfasdf-%d", seed)); + SetExtensionSettings(test()->verifier(), extension0, settings); + SetExtensionSettings(test()->GetProfile(0), extension0, settings); + } + { + // Write the same data to extension1 from both profiles. + DictionaryValue settings; + settings.SetString("asdf", StringPrintf("asdfasdf-%d", seed)); + settings.SetString("qwer", StringPrintf("qwerqwer-%d", seed)); + SetExtensionSettingsForAllProfiles(extension1, settings); + } + { + // Write different data to extension2 from each profile. + DictionaryValue settings0; + settings0.SetString("zxcv", StringPrintf("zxcvzxcv-%d", seed)); + SetExtensionSettings(test()->verifier(), extension2, settings0); + SetExtensionSettings(test()->GetProfile(0), extension2, settings0); + + DictionaryValue settings1; + settings1.SetString("1324", StringPrintf("12341234-%d", seed)); + settings1.SetString("5687", StringPrintf("56785678-%d", seed)); + SetExtensionSettings(test()->verifier(), extension2, settings1); + SetExtensionSettings(test()->GetProfile(1), extension2, settings1); + } +} + +class TwoClientExtensionSettingsSyncTest : public SyncTest { + public: + TwoClientExtensionSettingsSyncTest() : SyncTest(TWO_CLIENT) {} + virtual ~TwoClientExtensionSettingsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientExtensionSettingsSyncTest); +}; + +// For three independent extensions: +// +// Set up each extension with the same (but not necessarily empty) settings for +// all profiles, start syncing, add some new settings, sync, mutate those +// settings, sync. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionSettingsSyncTest, + StartWithSameSettings) { + ASSERT_TRUE(SetupClients()); + + const std::string& extension0 = InstallExtensionForAllProfiles(0); + const std::string& extension1 = InstallExtensionForAllProfiles(1); + const std::string& extension2 = InstallExtensionForAllProfiles(2); + + { + // Leave extension0 empty. + } + { + DictionaryValue settings; + settings.SetString("foo", "bar"); + SetExtensionSettingsForAllProfiles(extension1, settings); + } + { + DictionaryValue settings; + settings.SetString("foo", "bar"); + settings.SetString("baz", "qux"); + SetExtensionSettingsForAllProfiles(extension2, settings); + } + + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); + + MutateSomeSettings(0, extension0, extension1, extension2); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); + + MutateSomeSettings(1, extension0, extension1, extension2); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); +} + +// For three independent extensions: +// +// Set up each extension with different settings for each profile, start +// syncing, add some settings, sync, mutate those settings, sync, have a no-op +// (non-)change to those settings, sync, mutate again, sync. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionSettingsSyncTest, + StartWithDifferentSettings) { + ASSERT_TRUE(SetupClients()); + + const std::string& extension0 = InstallExtensionForAllProfiles(0); + const std::string& extension1 = InstallExtensionForAllProfiles(1); + const std::string& extension2 = InstallExtensionForAllProfiles(2); + + { + // Leave extension0 empty again for no particular reason other than it's + // the only remaining unique combination given the other 2 tests have + // (empty, nonempty) and (nonempty, nonempty) configurations. We can't test + // (nonempty, nonempty) because the merging will provide unpredictable + // results, so test (empty, empty). + } + { + DictionaryValue settings; + settings.SetString("foo", "bar"); + SetExtensionSettings(test()->verifier(), extension1, settings); + SetExtensionSettings(test()->GetProfile(0), extension1, settings); + } + { + DictionaryValue settings; + settings.SetString("foo", "bar"); + settings.SetString("baz", "qux"); + SetExtensionSettings(test()->verifier(), extension2, settings); + SetExtensionSettings(test()->GetProfile(1), extension2, settings); + } + + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); + + MutateSomeSettings(2, extension0, extension1, extension2); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); + + MutateSomeSettings(3, extension0, extension1, extension2); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); + + // Test a round of no-ops once, for sanity. Ideally we'd want to assert that + // this causes no sync activity, but that sounds tricky. + MutateSomeSettings(3, extension0, extension1, extension2); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); + + MutateSomeSettings(4, extension0, extension1, extension2); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllExtensionSettingsSameAsVerifier()); +} + +} // namespace |