diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-02 22:16:32 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-02 22:16:32 +0000 |
commit | 1695f10ff0d39d021782b3ab67013ec2c71c780c (patch) | |
tree | 2d59f7f859d59c1a81f8f5a2f313dad379cf2577 /chrome/browser | |
parent | 2bdb6e8a833382113f1d8c9bb6fb6cf45f7e8dd4 (diff) | |
download | chromium_src-1695f10ff0d39d021782b3ab67013ec2c71c780c.zip chromium_src-1695f10ff0d39d021782b3ab67013ec2c71c780c.tar.gz chromium_src-1695f10ff0d39d021782b3ab67013ec2c71c780c.tar.bz2 |
Move sync test code out of chrome/test
BUG=90905
Review URL: http://codereview.chromium.org/7828055
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99464 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
114 files changed, 13911 insertions, 48 deletions
diff --git a/chrome/browser/sync/abstract_profile_sync_service_test.cc b/chrome/browser/sync/abstract_profile_sync_service_test.cc index 640b273..01f379f 100644 --- a/chrome/browser/sync/abstract_profile_sync_service_test.cc +++ b/chrome/browser/sync/abstract_profile_sync_service_test.cc @@ -10,8 +10,8 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/test_profile_sync_service.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "chrome/browser/sync/util/cryptographer.h" -#include "chrome/test/sync/engine/test_id_factory.h" using browser_sync::TestIdFactory; using sync_api::UserShare; diff --git a/chrome/browser/sync/backend_migrator_unittest.cc b/chrome/browser/sync/backend_migrator_unittest.cc index 3d254b8..2c49b70 100644 --- a/chrome/browser/sync/backend_migrator_unittest.cc +++ b/chrome/browser/sync/backend_migrator_unittest.cc @@ -12,8 +12,8 @@ #include "chrome/browser/sync/protocol/sync.pb.h" #include "chrome/browser/sync/sessions/session_state.h" #include "chrome/browser/sync/syncable/directory_manager.h" +#include "chrome/browser/sync/test/engine/test_user_share.h" #include "chrome/common/chrome_notification_types.h" -#include "chrome/test/sync/engine/test_user_share.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/sync/engine/DEPS b/chrome/browser/sync/engine/DEPS index 0142088..59174bf 100644 --- a/chrome/browser/sync/engine/DEPS +++ b/chrome/browser/sync/engine/DEPS @@ -1,7 +1,6 @@ include_rules = [ "-chrome", "+chrome/test/base", - "+chrome/test/sync", "+chrome/browser/sync/engine", "+chrome/browser/sync/js", @@ -9,6 +8,7 @@ include_rules = [ "+chrome/browser/sync/protocol", "+chrome/browser/sync/sessions", "+chrome/browser/sync/syncable", + "+chrome/browser/sync/test", "+chrome/browser/sync/util", # TODO(rlarocque) 19878: Move remaining syncapi-related headers to diff --git a/chrome/browser/sync/engine/apply_updates_command_unittest.cc b/chrome/browser/sync/engine/apply_updates_command_unittest.cc index aa32c71..6fcb2868 100644 --- a/chrome/browser/sync/engine/apply_updates_command_unittest.cc +++ b/chrome/browser/sync/engine/apply_updates_command_unittest.cc @@ -17,8 +17,8 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/syncable/syncable_id.h" -#include "chrome/test/sync/engine/syncer_command_test.h" -#include "chrome/test/sync/engine/test_id_factory.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "testing/gtest/include/gtest/gtest.h" namespace browser_sync { diff --git a/chrome/browser/sync/engine/build_commit_command_unittest.cc b/chrome/browser/sync/engine/build_commit_command_unittest.cc index 24b139b..d924517 100644 --- a/chrome/browser/sync/engine/build_commit_command_unittest.cc +++ b/chrome/browser/sync/engine/build_commit_command_unittest.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/sync/engine/build_commit_command.h" -#include "chrome/test/sync/engine/syncer_command_test.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" namespace browser_sync { diff --git a/chrome/browser/sync/engine/cleanup_disabled_types_command_unittest.cc b/chrome/browser/sync/engine/cleanup_disabled_types_command_unittest.cc index 02ec54d..5ae0c78 100644 --- a/chrome/browser/sync/engine/cleanup_disabled_types_command_unittest.cc +++ b/chrome/browser/sync/engine/cleanup_disabled_types_command_unittest.cc @@ -8,7 +8,7 @@ #include "chrome/browser/sync/engine/syncer_end_command.h" #include "chrome/browser/sync/sessions/sync_session.h" -#include "chrome/test/sync/engine/syncer_command_test.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gmock/include/gmock/gmock.h" diff --git a/chrome/browser/sync/engine/clear_data_command_unittest.cc b/chrome/browser/sync/engine/clear_data_command_unittest.cc index 4ae4c8b..f4739a2 100644 --- a/chrome/browser/sync/engine/clear_data_command_unittest.cc +++ b/chrome/browser/sync/engine/clear_data_command_unittest.cc @@ -8,9 +8,9 @@ #include "chrome/browser/sync/protocol/preference_specifics.pb.h" #include "chrome/browser/sync/protocol/sync.pb.h" #include "chrome/browser/sync/syncable/directory_manager.h" -#include "chrome/test/sync/engine/proto_extension_validator.h" -#include "chrome/test/sync/engine/syncer_command_test.h" -#include "chrome/test/sync/sessions/test_scoped_session_event_listener.h" +#include "chrome/browser/sync/test/engine/proto_extension_validator.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" +#include "chrome/browser/sync/test/sessions/test_scoped_session_event_listener.h" namespace browser_sync { diff --git a/chrome/browser/sync/engine/download_updates_command_unittest.cc b/chrome/browser/sync/engine/download_updates_command_unittest.cc index 4bc22f1..1e2aa2f 100644 --- a/chrome/browser/sync/engine/download_updates_command_unittest.cc +++ b/chrome/browser/sync/engine/download_updates_command_unittest.cc @@ -8,8 +8,8 @@ #include "chrome/browser/sync/protocol/preference_specifics.pb.h" #include "chrome/browser/sync/protocol/sync.pb.h" #include "chrome/browser/sync/syncable/directory_manager.h" -#include "chrome/test/sync/engine/proto_extension_validator.h" -#include "chrome/test/sync/engine/syncer_command_test.h" +#include "chrome/browser/sync/test/engine/proto_extension_validator.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" namespace browser_sync { diff --git a/chrome/browser/sync/engine/process_commit_response_command_unittest.cc b/chrome/browser/sync/engine/process_commit_response_command_unittest.cc index bfa97f2..a428622 100644 --- a/chrome/browser/sync/engine/process_commit_response_command_unittest.cc +++ b/chrome/browser/sync/engine/process_commit_response_command_unittest.cc @@ -14,8 +14,8 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/syncable/syncable_id.h" -#include "chrome/test/sync/engine/syncer_command_test.h" -#include "chrome/test/sync/engine/test_id_factory.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "testing/gtest/include/gtest/gtest.h" namespace browser_sync { diff --git a/chrome/browser/sync/engine/sync_scheduler_unittest.cc b/chrome/browser/sync/engine/sync_scheduler_unittest.cc index ad58f71..57e05c1 100644 --- a/chrome/browser/sync/engine/sync_scheduler_unittest.cc +++ b/chrome/browser/sync/engine/sync_scheduler_unittest.cc @@ -13,8 +13,8 @@ #include "chrome/browser/sync/engine/sync_scheduler.h" #include "chrome/browser/sync/engine/syncer.h" #include "chrome/browser/sync/sessions/test_util.h" -#include "chrome/test/sync/engine/mock_connection_manager.h" -#include "chrome/test/sync/engine/test_directory_setter_upper.h" +#include "chrome/browser/sync/test/engine/mock_connection_manager.h" +#include "chrome/browser/sync/test/engine/test_directory_setter_upper.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gmock/include/gmock/gmock.h" diff --git a/chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc b/chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc index 911c5db..2a581b2 100644 --- a/chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc +++ b/chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc @@ -8,8 +8,8 @@ #include "chrome/browser/sync/engine/sync_scheduler.h" #include "chrome/browser/sync/sessions/sync_session_context.h" #include "chrome/browser/sync/sessions/test_util.h" -#include "chrome/test/sync/engine/mock_connection_manager.h" -#include "chrome/test/sync/engine/test_directory_setter_upper.h" +#include "chrome/browser/sync/test/engine/mock_connection_manager.h" +#include "chrome/browser/sync/test/engine/test_directory_setter_upper.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/sync/engine/syncer_proto_util_unittest.cc b/chrome/browser/sync/engine/syncer_proto_util_unittest.cc index 0a2bc9a..2b9fcbb 100644 --- a/chrome/browser/sync/engine/syncer_proto_util_unittest.cc +++ b/chrome/browser/sync/engine/syncer_proto_util_unittest.cc @@ -12,8 +12,8 @@ #include "chrome/browser/sync/syncable/blob.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" -#include "chrome/test/sync/engine/mock_connection_manager.h" -#include "chrome/test/sync/engine/test_directory_setter_upper.h" +#include "chrome/browser/sync/test/engine/mock_connection_manager.h" +#include "chrome/browser/sync/test/engine/test_directory_setter_upper.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/sync/engine/syncer_unittest.cc b/chrome/browser/sync/engine/syncer_unittest.cc index 4e39352..093d473 100644 --- a/chrome/browser/sync/engine/syncer_unittest.cc +++ b/chrome/browser/sync/engine/syncer_unittest.cc @@ -34,10 +34,10 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/syncable/syncable.h" -#include "chrome/test/sync/engine/mock_connection_manager.h" -#include "chrome/test/sync/engine/test_directory_setter_upper.h" -#include "chrome/test/sync/engine/test_id_factory.h" -#include "chrome/test/sync/engine/test_syncable_utils.h" +#include "chrome/browser/sync/test/engine/mock_connection_manager.h" +#include "chrome/browser/sync/test/engine/test_directory_setter_upper.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" +#include "chrome/browser/sync/test/engine/test_syncable_utils.h" #include "testing/gtest/include/gtest/gtest.h" using base::TimeDelta; diff --git a/chrome/browser/sync/engine/verify_updates_command_unittest.cc b/chrome/browser/sync/engine/verify_updates_command_unittest.cc index 03f6e49..a6fa195 100644 --- a/chrome/browser/sync/engine/verify_updates_command_unittest.cc +++ b/chrome/browser/sync/engine/verify_updates_command_unittest.cc @@ -10,7 +10,7 @@ #include "chrome/browser/sync/engine/mock_model_safe_workers.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/syncable/syncable_id.h" -#include "chrome/test/sync/engine/syncer_command_test.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" #include "testing/gtest/include/gtest/gtest.h" namespace browser_sync { diff --git a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc index 8d40955..806ff12 100644 --- a/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc +++ b/chrome/browser/sync/glue/sync_backend_registrar_unittest.cc @@ -7,8 +7,8 @@ #include "chrome/browser/sync/glue/change_processor_mock.h" #include "chrome/browser/sync/glue/ui_model_worker.h" #include "chrome/browser/sync/syncable/model_type.h" +#include "chrome/browser/sync/test/engine/test_user_share.h" #include "chrome/test/base/testing_profile.h" -#include "chrome/test/sync/engine/test_user_share.h" #include "content/browser/browser_thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/sync/internal_api/DEPS b/chrome/browser/sync/internal_api/DEPS index a393f32..f3e71ab 100644 --- a/chrome/browser/sync/internal_api/DEPS +++ b/chrome/browser/sync/internal_api/DEPS @@ -1,7 +1,6 @@ include_rules = [ "-chrome", "+chrome/test/base", - "+chrome/test/sync", "+chrome/browser/sync", "-chrome/browser/sync/api", diff --git a/chrome/browser/sync/internal_api/syncapi_unittest.cc b/chrome/browser/sync/internal_api/syncapi_unittest.cc index 4ee77b7..50e3a36 100644 --- a/chrome/browser/sync/internal_api/syncapi_unittest.cc +++ b/chrome/browser/sync/internal_api/syncapi_unittest.cc @@ -45,9 +45,9 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/syncable/syncable_id.h" +#include "chrome/browser/sync/test/engine/test_user_share.h" #include "chrome/browser/sync/util/cryptographer.h" #include "chrome/test/base/values_test_util.h" -#include "chrome/test/sync/engine/test_user_share.h" #include "content/browser/browser_thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/sync/js/DEPS b/chrome/browser/sync/js/DEPS index 3b29013..3a59572 100644 --- a/chrome/browser/sync/js/DEPS +++ b/chrome/browser/sync/js/DEPS @@ -1,6 +1,5 @@ include_rules = [ "-chrome", - "+chrome/test/sync", "+chrome/browser/sync/js", @@ -8,6 +7,7 @@ include_rules = [ "+chrome/browser/sync/sessions/session_state.h", "+chrome/browser/sync/syncable/model_type.h", "+chrome/browser/sync/syncable/transaction_observer.h", + "+chrome/browser/sync/test", # TODO(akalin): this should be in base. "+chrome/browser/sync/weak_handle.h", diff --git a/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc b/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc index 4ffd253..148091d 100644 --- a/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc +++ b/chrome/browser/sync/js/js_sync_manager_observer_unittest.cc @@ -19,8 +19,8 @@ #include "chrome/browser/sync/js/js_test_util.h" #include "chrome/browser/sync/sessions/session_state.h" #include "chrome/browser/sync/syncable/model_type.h" +#include "chrome/browser/sync/test/engine/test_user_share.h" #include "chrome/browser/sync/weak_handle.h" -#include "chrome/test/sync/engine/test_user_share.h" #include "testing/gtest/include/gtest/gtest.h" namespace browser_sync { diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc index 7f46b91..2fc2b7f 100644 --- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc @@ -40,13 +40,13 @@ #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/test_profile_sync_service.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "chrome/browser/webdata/autofill_change.h" #include "chrome/browser/webdata/autofill_entry.h" #include "chrome/browser/webdata/autofill_table.h" #include "chrome/browser/webdata/web_database.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/net/gaia/gaia_constants.h" -#include "chrome/test/sync/engine/test_id_factory.h" #include "content/browser/browser_thread.h" #include "content/common/notification_source.h" #include "testing/gmock/include/gmock/gmock.h" diff --git a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc index 39e0306..a00414e 100644 --- a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc @@ -30,10 +30,10 @@ #include "chrome/browser/sync/internal_api/write_node.h" #include "chrome/browser/sync/internal_api/write_transaction.h" #include "chrome/browser/sync/syncable/directory_manager.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" +#include "chrome/browser/sync/test/engine/test_user_share.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/testing_profile.h" -#include "chrome/test/sync/engine/test_id_factory.h" -#include "chrome/test/sync/engine/test_user_share.h" #include "content/browser/browser_thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc index 175018a..8e45e78 100644 --- a/chrome/browser/sync/profile_sync_service_password_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc @@ -30,11 +30,11 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/test_profile_sync_service.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/profile_mock.h" -#include "chrome/test/sync/engine/test_id_factory.h" #include "content/browser/browser_thread.h" #include "content/common/notification_observer_mock.h" #include "content/common/notification_source.h" diff --git a/chrome/browser/sync/profile_sync_service_session_unittest.cc b/chrome/browser/sync/profile_sync_service_session_unittest.cc index e47aa20..b1c7309 100644 --- a/chrome/browser/sync/profile_sync_service_session_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_session_unittest.cc @@ -31,12 +31,12 @@ #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/test_profile_sync_service.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/profile_mock.h" #include "chrome/test/base/testing_profile.h" -#include "chrome/test/sync/engine/test_id_factory.h" #include "content/browser/browser_thread.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc index 4bcd09a..103e7f0 100644 --- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc @@ -32,11 +32,11 @@ #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/test_profile_sync_service.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/test/base/profile_mock.h" #include "chrome/test/base/testing_profile.h" -#include "chrome/test/sync/engine/test_id_factory.h" #include "content/common/notification_service.h" #include "googleurl/src/gurl.h" #include "testing/gmock/include/gmock/gmock.h" diff --git a/chrome/browser/sync/sessions/DEPS b/chrome/browser/sync/sessions/DEPS index 0d7660a..2a4b7d8 100644 --- a/chrome/browser/sync/sessions/DEPS +++ b/chrome/browser/sync/sessions/DEPS @@ -1,12 +1,12 @@ include_rules = [ "-chrome", "+chrome/test/base", - "+chrome/test/sync", "+chrome/browser/sync/engine", "+chrome/browser/sync/protocol", "+chrome/browser/sync/sessions", "+chrome/browser/sync/syncable", + "+chrome/browser/sync/test", "+chrome/browser/sync/util", "-chrome/browser/sync/internal_api", diff --git a/chrome/browser/sync/sessions/ordered_commit_set_unittest.cc b/chrome/browser/sync/sessions/ordered_commit_set_unittest.cc index 0c9db8e..cf1f4d9 100644 --- a/chrome/browser/sync/sessions/ordered_commit_set_unittest.cc +++ b/chrome/browser/sync/sessions/ordered_commit_set_unittest.cc @@ -4,7 +4,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "chrome/browser/sync/sessions/ordered_commit_set.h" -#include "chrome/test/sync/engine/test_id_factory.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" using std::vector; diff --git a/chrome/browser/sync/sessions/status_controller_unittest.cc b/chrome/browser/sync/sessions/status_controller_unittest.cc index bd7296b..bebbd18 100644 --- a/chrome/browser/sync/sessions/status_controller_unittest.cc +++ b/chrome/browser/sync/sessions/status_controller_unittest.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/sync/sessions/sync_session.h" -#include "chrome/test/sync/engine/test_id_factory.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "testing/gtest/include/gtest/gtest.h" namespace browser_sync { diff --git a/chrome/browser/sync/sessions/sync_session_unittest.cc b/chrome/browser/sync/sessions/sync_session_unittest.cc index 4c58b45..34c91de 100644 --- a/chrome/browser/sync/sessions/sync_session_unittest.cc +++ b/chrome/browser/sync/sessions/sync_session_unittest.cc @@ -14,7 +14,7 @@ #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/model_type.h" #include "chrome/browser/sync/syncable/syncable.h" -#include "chrome/test/sync/engine/test_directory_setter_upper.h" +#include "chrome/browser/sync/test/engine/test_directory_setter_upper.h" #include "testing/gtest/include/gtest/gtest.h" using syncable::WriteTransaction; diff --git a/chrome/browser/sync/syncable/DEPS b/chrome/browser/sync/syncable/DEPS index 032cd30..53bed5c 100644 --- a/chrome/browser/sync/syncable/DEPS +++ b/chrome/browser/sync/syncable/DEPS @@ -1,11 +1,11 @@ include_rules = [ "-chrome", "+chrome/test/base", - "+chrome/test/sync", "+chrome/browser/sync/protocol", "+chrome/browser/sync/sessions", "+chrome/browser/sync/syncable", + "+chrome/browser/sync/test", "+chrome/browser/sync/util", # this file is wierd. diff --git a/chrome/browser/sync/syncable/syncable_id_unittest.cc b/chrome/browser/sync/syncable/syncable_id_unittest.cc index 56ab4a8..9703861 100644 --- a/chrome/browser/sync/syncable/syncable_id_unittest.cc +++ b/chrome/browser/sync/syncable/syncable_id_unittest.cc @@ -8,8 +8,8 @@ #include "base/memory/scoped_ptr.h" #include "base/values.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "chrome/test/base/values_test_util.h" -#include "chrome/test/sync/engine/test_id_factory.h" #include "testing/gtest/include/gtest/gtest.h" using std::vector; diff --git a/chrome/browser/sync/syncable/syncable_mock.h b/chrome/browser/sync/syncable/syncable_mock.h index 51692a7..656b3d5 100644 --- a/chrome/browser/sync/syncable/syncable_mock.h +++ b/chrome/browser/sync/syncable/syncable_mock.h @@ -9,7 +9,7 @@ #include <string> #include "chrome/browser/sync/syncable/syncable.h" -#include "chrome/test/sync/null_directory_change_delegate.h" +#include "chrome/browser/sync/test/null_directory_change_delegate.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/sync/syncable/syncable_unittest.cc b/chrome/browser/sync/syncable/syncable_unittest.cc index e9d20e2..004e739 100644 --- a/chrome/browser/sync/syncable/syncable_unittest.cc +++ b/chrome/browser/sync/syncable/syncable_unittest.cc @@ -36,10 +36,10 @@ #include "chrome/browser/sync/syncable/directory_backing_store.h" #include "chrome/browser/sync/syncable/directory_change_delegate.h" #include "chrome/browser/sync/syncable/directory_manager.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" +#include "chrome/browser/sync/test/engine/test_syncable_utils.h" +#include "chrome/browser/sync/test/null_directory_change_delegate.h" #include "chrome/test/base/values_test_util.h" -#include "chrome/test/sync/engine/test_id_factory.h" -#include "chrome/test/sync/engine/test_syncable_utils.h" -#include "chrome/test/sync/null_directory_change_delegate.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/sqlite/sqlite3.h" diff --git a/chrome/browser/sync/test/engine/mock_connection_manager.cc b/chrome/browser/sync/test/engine/mock_connection_manager.cc new file mode 100644 index 0000000..22e11c0 --- /dev/null +++ b/chrome/browser/sync/test/engine/mock_connection_manager.cc @@ -0,0 +1,624 @@ +// Copyright (c) 2011 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. +// +// Mock ServerConnectionManager class for use in client regression tests. + +#include "chrome/browser/sync/test/engine/mock_connection_manager.h" + +#include <map> + +#include "base/stringprintf.h" +#include "base/tracked.h" +#include "chrome/browser/sync/engine/syncer_proto_util.h" +#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" +#include "testing/gtest/include/gtest/gtest.h" + +using browser_sync::HttpResponse; +using browser_sync::ServerConnectionManager; +using browser_sync::ServerConnectionEventListener; +using browser_sync::ServerConnectionEvent; +using browser_sync::SyncerProtoUtil; +using browser_sync::TestIdFactory; +using std::map; +using std::string; +using sync_pb::ClientToServerMessage; +using sync_pb::ClientToServerResponse; +using sync_pb::CommitMessage; +using sync_pb::CommitResponse; +using sync_pb::CommitResponse_EntryResponse; +using sync_pb::GetUpdatesMessage; +using sync_pb::SyncEntity; +using syncable::DirectoryManager; +using syncable::FIRST_REAL_MODEL_TYPE; +using syncable::MODEL_TYPE_COUNT; +using syncable::ModelType; +using syncable::ScopedDirLookup; +using syncable::WriteTransaction; + +MockConnectionManager::MockConnectionManager(DirectoryManager* dirmgr, + const string& name) + : ServerConnectionManager("unused", 0, false, "version"), + conflict_all_commits_(false), + conflict_n_commits_(0), + next_new_id_(10000), + store_birthday_("Store BDay!"), + store_birthday_sent_(false), + client_stuck_(false), + commit_time_rename_prepended_string_(""), + fail_next_postbuffer_(false), + directory_manager_(dirmgr), + directory_name_(name), + mid_commit_observer_(NULL), + throttling_(false), + fail_with_auth_invalid_(false), + fail_non_periodic_get_updates_(false), + client_command_(NULL), + next_position_in_parent_(2), + use_legacy_bookmarks_protocol_(false), + num_get_updates_requests_(0) { + server_reachable_ = true; + SetNewTimestamp(0); +}; + +MockConnectionManager::~MockConnectionManager() { + EXPECT_TRUE(update_queue_.empty()) << "Unfetched updates."; +} + +void MockConnectionManager::SetCommitTimeRename(string prepend) { + commit_time_rename_prepended_string_ = prepend; +} + +void MockConnectionManager::SetMidCommitCallback(Callback0::Type* callback) { + mid_commit_callback_.reset(callback); +} + +void MockConnectionManager::SetMidCommitObserver( + MockConnectionManager::MidCommitObserver* observer) { + mid_commit_observer_ = observer; +} + +bool MockConnectionManager::PostBufferToPath(PostBufferParams* params, + const string& path, + const string& auth_token, + browser_sync::ScopedServerStatusWatcher* watcher) { + ClientToServerMessage post; + CHECK(post.ParseFromString(params->buffer_in)); + last_request_.CopyFrom(post); + client_stuck_ = post.sync_problem_detected(); + ClientToServerResponse response; + response.Clear(); + + ScopedDirLookup directory(directory_manager_, directory_name_); + // For any non-AUTHENTICATE requests, a valid directory should be set up. + // If the Directory's locked when we do this, it's a problem as in normal + // use this function could take a while to return because it accesses the + // network. As we can't test this we do the next best thing and hang here + // when there's an issue. + if (post.message_contents() != ClientToServerMessage::AUTHENTICATE) { + CHECK(directory.good()); + WriteTransaction wt(FROM_HERE, syncable::UNITTEST, directory); + } + + if (fail_next_postbuffer_) { + fail_next_postbuffer_ = false; + return false; + } + + if (!server_reachable_) { + params->response.server_status = HttpResponse::CONNECTION_UNAVAILABLE; + return false; + } + + // Default to an ok connection. + params->response.server_status = HttpResponse::SERVER_CONNECTION_OK; + response.set_error_code(ClientToServerResponse::SUCCESS); + const string current_store_birthday = store_birthday(); + response.set_store_birthday(current_store_birthday); + if (post.has_store_birthday() && post.store_birthday() != + current_store_birthday) { + response.set_error_code(ClientToServerResponse::NOT_MY_BIRTHDAY); + response.set_error_message("Merry Unbirthday!"); + response.SerializeToString(¶ms->buffer_out); + store_birthday_sent_ = true; + return true; + } + bool result = true; + EXPECT_TRUE(!store_birthday_sent_ || post.has_store_birthday() || + post.message_contents() == ClientToServerMessage::AUTHENTICATE); + store_birthday_sent_ = true; + + if (post.message_contents() == ClientToServerMessage::COMMIT) { + ProcessCommit(&post, &response); + } else if (post.message_contents() == ClientToServerMessage::GET_UPDATES) { + ProcessGetUpdates(&post, &response); + } else if (post.message_contents() == ClientToServerMessage::AUTHENTICATE) { + ProcessAuthenticate(&post, &response, auth_token); + } else if (post.message_contents() == ClientToServerMessage::CLEAR_DATA) { + ProcessClearData(&post, &response); + } else { + EXPECT_TRUE(false) << "Unknown/unsupported ClientToServerMessage"; + return false; + } + if (client_command_.get()) { + response.mutable_client_command()->CopyFrom(*client_command_.get()); + } + + { + base::AutoLock lock(response_code_override_lock_); + if (throttling_) { + response.set_error_code(ClientToServerResponse::THROTTLED); + throttling_ = false; + } + + if (fail_with_auth_invalid_) + response.set_error_code(ClientToServerResponse::AUTH_INVALID); + } + + response.SerializeToString(¶ms->buffer_out); + if (post.message_contents() == ClientToServerMessage::COMMIT && + mid_commit_callback_.get()) { + mid_commit_callback_->Run(); + } + if (mid_commit_observer_) { + mid_commit_observer_->Observe(); + } + + return result; +} + +bool MockConnectionManager::IsServerReachable() { + return true; +} + +bool MockConnectionManager::IsUserAuthenticated() { + return true; +} + +sync_pb::GetUpdatesResponse* MockConnectionManager::GetUpdateResponse() { + if (update_queue_.empty()) { + NextUpdateBatch(); + } + return &update_queue_.back(); +} + +void MockConnectionManager::AddDefaultBookmarkData(sync_pb::SyncEntity* entity, + bool is_folder) { + if (use_legacy_bookmarks_protocol_) { + sync_pb::SyncEntity_BookmarkData* data = entity->mutable_bookmarkdata(); + data->set_bookmark_folder(is_folder); + + if (!is_folder) { + data->set_bookmark_url("http://google.com"); + } + } else { + entity->set_folder(is_folder); + entity->mutable_specifics()->MutableExtension(sync_pb::bookmark); + if (!is_folder) { + entity->mutable_specifics()->MutableExtension(sync_pb::bookmark)-> + set_url("http://google.com"); + } + } +} + +SyncEntity* MockConnectionManager::AddUpdateDirectory(int id, + int parent_id, + string name, + int64 version, + int64 sync_ts) { + return AddUpdateDirectory(TestIdFactory::FromNumber(id), + TestIdFactory::FromNumber(parent_id), + name, + version, + sync_ts); +} + +sync_pb::ClientCommand* MockConnectionManager::GetNextClientCommand() { + if (!client_command_.get()) + client_command_.reset(new sync_pb::ClientCommand()); + return client_command_.get(); +} + +SyncEntity* MockConnectionManager::AddUpdateBookmark(int id, int parent_id, + string name, int64 version, + int64 sync_ts) { + return AddUpdateBookmark(TestIdFactory::FromNumber(id), + TestIdFactory::FromNumber(parent_id), + name, + version, + sync_ts); +} + +SyncEntity* MockConnectionManager::AddUpdateFull(string id, string parent_id, + string name, int64 version, + int64 sync_ts, bool is_dir) { + SyncEntity* ent = GetUpdateResponse()->add_entries(); + ent->set_id_string(id); + ent->set_parent_id_string(parent_id); + ent->set_non_unique_name(name); + ent->set_name(name); + ent->set_version(version); + ent->set_sync_timestamp(sync_ts); + ent->set_mtime(sync_ts); + ent->set_ctime(1); + ent->set_position_in_parent(GeneratePositionInParent()); + AddDefaultBookmarkData(ent, is_dir); + + return ent; +} + +SyncEntity* MockConnectionManager::AddUpdateDirectory(string id, + string parent_id, + string name, + int64 version, + int64 sync_ts) { + return AddUpdateFull(id, parent_id, name, version, sync_ts, true); +} + +SyncEntity* MockConnectionManager::AddUpdateBookmark(string id, + string parent_id, + string name, int64 version, + int64 sync_ts) { + return AddUpdateFull(id, parent_id, name, version, sync_ts, false); +} + +SyncEntity* MockConnectionManager::AddUpdateFromLastCommit() { + EXPECT_EQ(1, last_sent_commit().entries_size()); + EXPECT_EQ(1, last_commit_response().entryresponse_size()); + EXPECT_EQ(CommitResponse::SUCCESS, + last_commit_response().entryresponse(0).response_type()); + + if (last_sent_commit().entries(0).deleted()) { + AddUpdateTombstone(syncable::Id::CreateFromServerId( + last_sent_commit().entries(0).id_string())); + } else { + SyncEntity* ent = GetUpdateResponse()->add_entries(); + ent->CopyFrom(last_sent_commit().entries(0)); + ent->clear_insert_after_item_id(); + ent->clear_old_parent_id(); + ent->set_position_in_parent( + last_commit_response().entryresponse(0).position_in_parent()); + ent->set_version( + last_commit_response().entryresponse(0).version()); + ent->set_id_string( + last_commit_response().entryresponse(0).id_string()); + // Tests don't currently care about the following: + // originator_cache_guid, originator_client_item_id, parent_id_string, + // name, non_unique_name. + } + return GetMutableLastUpdate(); +} + +void MockConnectionManager::AddUpdateTombstone(const syncable::Id& id) { + // Tombstones have only the ID set and dummy values for the required fields. + SyncEntity* ent = GetUpdateResponse()->add_entries(); + ent->set_id_string(id.GetServerId()); + ent->set_version(0); + ent->set_name(""); + ent->set_deleted(true); +} + +void MockConnectionManager::SetLastUpdateDeleted() { + // Tombstones have only the ID set. Wipe anything else. + string id_string = GetMutableLastUpdate()->id_string(); + GetUpdateResponse()->mutable_entries()->RemoveLast(); + AddUpdateTombstone(syncable::Id::CreateFromServerId(id_string)); +} + +void MockConnectionManager::SetLastUpdateOriginatorFields( + const string& client_id, + const string& entry_id) { + GetMutableLastUpdate()->set_originator_cache_guid(client_id); + GetMutableLastUpdate()->set_originator_client_item_id(entry_id); +} + +void MockConnectionManager::SetLastUpdateServerTag(const string& tag) { + GetMutableLastUpdate()->set_server_defined_unique_tag(tag); +} + +void MockConnectionManager::SetLastUpdateClientTag(const string& tag) { + GetMutableLastUpdate()->set_client_defined_unique_tag(tag); +} + +void MockConnectionManager::SetLastUpdatePosition(int64 server_position) { + GetMutableLastUpdate()->set_position_in_parent(server_position); +} + +void MockConnectionManager::SetNewTimestamp(int ts) { + next_token_ = base::StringPrintf("mock connection ts = %d", ts); + ApplyToken(); +} + +void MockConnectionManager::ApplyToken() { + if (!update_queue_.empty()) { + GetUpdateResponse()->clear_new_progress_marker(); + sync_pb::DataTypeProgressMarker* new_marker = + GetUpdateResponse()->add_new_progress_marker(); + new_marker->set_data_type_id(-1); // Invalid -- clients shouldn't see. + new_marker->set_token(next_token_); + } +} + +void MockConnectionManager::SetChangesRemaining(int64 timestamp) { + GetUpdateResponse()->set_changes_remaining(timestamp); +} + +void MockConnectionManager::ProcessGetUpdates(ClientToServerMessage* csm, + ClientToServerResponse* response) { + CHECK(csm->has_get_updates()); + ASSERT_EQ(csm->message_contents(), ClientToServerMessage::GET_UPDATES); + const GetUpdatesMessage& gu = csm->get_updates(); + num_get_updates_requests_++; + EXPECT_FALSE(gu.has_from_timestamp()); + EXPECT_FALSE(gu.has_requested_types()); + + if (fail_non_periodic_get_updates_) { + EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC, + gu.caller_info().source()); + } + + // Verify that the GetUpdates filter sent by the Syncer matches the test + // expectation. + for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { + ModelType model_type = syncable::ModelTypeFromInt(i); + sync_pb::DataTypeProgressMarker const* progress_marker = + GetProgressMarkerForType(gu.from_progress_marker(), model_type); + EXPECT_EQ(expected_filter_[i], (progress_marker != NULL)) + << "Syncer requested_types differs from test expectation."; + if (progress_marker) { + EXPECT_EQ((expected_payloads_.count(model_type) > 0 ? + expected_payloads_[model_type] : + std::string()), + progress_marker->notification_hint()); + } + } + + // Verify that the items we're about to send back to the client are of + // the types requested by the client. If this fails, it probably indicates + // a test bug. + EXPECT_TRUE(gu.fetch_folders()); + EXPECT_FALSE(gu.has_requested_types()); + if (update_queue_.empty()) { + GetUpdateResponse(); + } + sync_pb::GetUpdatesResponse* updates = &update_queue_.front(); + for (int i = 0; i < updates->entries_size(); ++i) { + if (!updates->entries(i).deleted()) { + ModelType entry_type = syncable::GetModelType(updates->entries(i)); + EXPECT_TRUE( + IsModelTypePresentInSpecifics(gu.from_progress_marker(), entry_type)) + << "Syncer did not request updates being provided by the test."; + } + } + + response->mutable_get_updates()->CopyFrom(*updates); + + // Set appropriate progress markers, overriding the value squirreled + // away by ApplyToken(). + std::string token = response->get_updates().new_progress_marker(0).token(); + response->mutable_get_updates()->clear_new_progress_marker(); + for (int i = 0; i < gu.from_progress_marker_size(); ++i) { + if (gu.from_progress_marker(i).token() != token) { + sync_pb::DataTypeProgressMarker* new_marker = + response->mutable_get_updates()->add_new_progress_marker(); + new_marker->set_data_type_id(gu.from_progress_marker(i).data_type_id()); + new_marker->set_token(token); + } + } + + update_queue_.pop_front(); +} + +void MockConnectionManager::SetClearUserDataResponseStatus( + sync_pb::ClientToServerResponse::ErrorType errortype ) { + // Note: this is not a thread-safe set, ok for now. NOT ok if tests + // run the syncer on the background thread while this method is called. + clear_user_data_response_errortype_ = errortype; +} + +void MockConnectionManager::ProcessClearData(ClientToServerMessage* csm, + ClientToServerResponse* response) { + CHECK(csm->has_clear_user_data()); + ASSERT_EQ(csm->message_contents(), ClientToServerMessage::CLEAR_DATA); + response->clear_user_data(); + response->set_error_code(clear_user_data_response_errortype_); +} + +void MockConnectionManager::ProcessAuthenticate( + ClientToServerMessage* csm, + ClientToServerResponse* response, + const std::string& auth_token) { + ASSERT_EQ(csm->message_contents(), ClientToServerMessage::AUTHENTICATE); + EXPECT_FALSE(auth_token.empty()); + + if (auth_token != valid_auth_token_) { + response->set_error_code(ClientToServerResponse::AUTH_INVALID); + return; + } + + response->set_error_code(ClientToServerResponse::SUCCESS); + response->mutable_authenticate()->CopyFrom(auth_response_); + auth_response_.Clear(); +} + +void MockConnectionManager::SetAuthenticationResponseInfo( + const std::string& valid_auth_token, + const std::string& user_display_name, + const std::string& user_display_email, + const std::string& user_obfuscated_id) { + valid_auth_token_ = valid_auth_token; + sync_pb::UserIdentification* user = auth_response_.mutable_user(); + user->set_display_name(user_display_name); + user->set_email(user_display_email); + user->set_obfuscated_id(user_obfuscated_id); +} + +bool MockConnectionManager::ShouldConflictThisCommit() { + bool conflict = false; + if (conflict_all_commits_) { + conflict = true; + } else if (conflict_n_commits_ > 0) { + conflict = true; + --conflict_n_commits_; + } + return conflict; +} + +void MockConnectionManager::ProcessCommit(ClientToServerMessage* csm, + ClientToServerResponse* response_buffer) { + CHECK(csm->has_commit()); + ASSERT_EQ(csm->message_contents(), ClientToServerMessage::COMMIT); + map <string, string> changed_ids; + const CommitMessage& commit_message = csm->commit(); + CommitResponse* commit_response = response_buffer->mutable_commit(); + commit_messages_->push_back(new CommitMessage); + commit_messages_->back()->CopyFrom(commit_message); + map<string, CommitResponse_EntryResponse*> response_map; + for (int i = 0; i < commit_message.entries_size() ; i++) { + const sync_pb::SyncEntity& entry = commit_message.entries(i); + CHECK(entry.has_id_string()); + string id = entry.id_string(); + ASSERT_LT(entry.name().length(), 256ul) << " name probably too long. True " + "server name checking not implemented"; + if (entry.version() == 0) { + // Relies on our new item string id format. (string representation of a + // negative number). + committed_ids_.push_back(syncable::Id::CreateFromClientString(id)); + } else { + committed_ids_.push_back(syncable::Id::CreateFromServerId(id)); + } + if (response_map.end() == response_map.find(id)) + response_map[id] = commit_response->add_entryresponse(); + CommitResponse_EntryResponse* er = response_map[id]; + if (ShouldConflictThisCommit()) { + er->set_response_type(CommitResponse::CONFLICT); + continue; + } + er->set_response_type(CommitResponse::SUCCESS); + er->set_version(entry.version() + 1); + if (!commit_time_rename_prepended_string_.empty()) { + // Commit time rename sent down from the server. + er->set_name(commit_time_rename_prepended_string_ + entry.name()); + } + string parent_id = entry.parent_id_string(); + // Remap id's we've already assigned. + if (changed_ids.end() != changed_ids.find(parent_id)) { + parent_id = changed_ids[parent_id]; + er->set_parent_id_string(parent_id); + } + if (entry.has_version() && 0 != entry.version()) { + er->set_id_string(id); // Allows verification. + } else { + string new_id = base::StringPrintf("mock_server:%d", next_new_id_++); + changed_ids[id] = new_id; + er->set_id_string(new_id); + } + } + commit_responses_->push_back(new CommitResponse(*commit_response)); +} + +SyncEntity* MockConnectionManager::AddUpdateDirectory( + syncable::Id id, syncable::Id parent_id, string name, int64 version, + int64 sync_ts) { + return AddUpdateDirectory(id.GetServerId(), parent_id.GetServerId(), + name, version, sync_ts); +} + +SyncEntity* MockConnectionManager::AddUpdateBookmark( + syncable::Id id, syncable::Id parent_id, string name, int64 version, + int64 sync_ts) { + return AddUpdateBookmark(id.GetServerId(), parent_id.GetServerId(), + name, version, sync_ts); +} + +SyncEntity* MockConnectionManager::GetMutableLastUpdate() { + sync_pb::GetUpdatesResponse* updates = GetUpdateResponse(); + EXPECT_GT(updates->entries_size(), 0); + return updates->mutable_entries()->Mutable(updates->entries_size() - 1); +} + +void MockConnectionManager::NextUpdateBatch() { + update_queue_.push_back(sync_pb::GetUpdatesResponse::default_instance()); + SetChangesRemaining(0); + ApplyToken(); +} + +const CommitMessage& MockConnectionManager::last_sent_commit() const { + EXPECT_TRUE(!commit_messages_.empty()); + return *commit_messages_->back(); +} + +const CommitResponse& MockConnectionManager::last_commit_response() const { + EXPECT_TRUE(!commit_responses_.empty()); + return *commit_responses_->back(); +} + +void MockConnectionManager::ThrottleNextRequest( + ResponseCodeOverrideRequestor* visitor) { + base::AutoLock lock(response_code_override_lock_); + throttling_ = true; + if (visitor) + visitor->OnOverrideComplete(); +} + +void MockConnectionManager::FailWithAuthInvalid( + ResponseCodeOverrideRequestor* visitor) { + base::AutoLock lock(response_code_override_lock_); + fail_with_auth_invalid_ = true; + if (visitor) + visitor->OnOverrideComplete(); +} + +void MockConnectionManager::StopFailingWithAuthInvalid( + ResponseCodeOverrideRequestor* visitor) { + base::AutoLock lock(response_code_override_lock_); + fail_with_auth_invalid_ = false; + if (visitor) + visitor->OnOverrideComplete(); +} + +bool MockConnectionManager::IsModelTypePresentInSpecifics( + const google::protobuf::RepeatedPtrField< + sync_pb::DataTypeProgressMarker>& filter, + syncable::ModelType value) { + int data_type_id = syncable::GetExtensionFieldNumberFromModelType(value); + for (int i = 0; i < filter.size(); ++i) { + if (filter.Get(i).data_type_id() == data_type_id) { + return true; + } + } + return false; +} + +sync_pb::DataTypeProgressMarker const* + MockConnectionManager::GetProgressMarkerForType( + const google::protobuf::RepeatedPtrField< + sync_pb::DataTypeProgressMarker>& filter, + syncable::ModelType value) { + int data_type_id = syncable::GetExtensionFieldNumberFromModelType(value); + for (int i = 0; i < filter.size(); ++i) { + if (filter.Get(i).data_type_id() == data_type_id) { + return &(filter.Get(i)); + } + } + return NULL; +} + +void MockConnectionManager::SetServerReachable() { + server_status_ = HttpResponse::SERVER_CONNECTION_OK; + server_reachable_ = true; + + FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_, + OnServerConnectionEvent( + ServerConnectionEvent(server_status_, server_reachable_))); +} + +void MockConnectionManager::SetServerNotReachable() { + server_status_ = HttpResponse::CONNECTION_UNAVAILABLE; + server_reachable_ = false; + + FOR_EACH_OBSERVER(ServerConnectionEventListener, listeners_, + OnServerConnectionEvent( + ServerConnectionEvent(server_status_, server_reachable_))); +} diff --git a/chrome/browser/sync/test/engine/mock_connection_manager.h b/chrome/browser/sync/test/engine/mock_connection_manager.h new file mode 100644 index 0000000..fe98699 --- /dev/null +++ b/chrome/browser/sync/test/engine/mock_connection_manager.h @@ -0,0 +1,364 @@ +// Copyright (c) 2011 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. +// +// Mock ServerConnectionManager class for use in client unit tests. + +#ifndef CHROME_BROWSER_SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_ +#pragma once + +#include <bitset> +#include <list> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_vector.h" +#include "chrome/browser/sync/engine/net/server_connection_manager.h" +#include "chrome/browser/sync/protocol/sync.pb.h" +#include "chrome/browser/sync/syncable/directory_manager.h" +#include "chrome/browser/sync/syncable/model_type.h" +#include "chrome/browser/sync/syncable/model_type_payload_map.h" + +namespace syncable { +class DirectoryManager; +class ScopedDirLookup; +} +namespace browser_sync { +struct HttpResponse; +} + +class MockConnectionManager : public browser_sync::ServerConnectionManager { + public: + class MidCommitObserver { + public: + virtual void Observe() = 0; + + protected: + virtual ~MidCommitObserver() {} + }; + + MockConnectionManager(syncable::DirectoryManager* dirmgr, + const std::string& name); + virtual ~MockConnectionManager(); + + // Overridden ServerConnectionManager functions. + virtual bool PostBufferToPath( + PostBufferParams*, + const std::string& path, + const std::string& auth_token, + browser_sync::ScopedServerStatusWatcher* watcher) OVERRIDE; + + virtual bool IsServerReachable() OVERRIDE; + virtual bool IsUserAuthenticated() OVERRIDE; + + // Control of commit response. + void SetMidCommitCallback(Callback0::Type* callback); + void SetMidCommitObserver(MidCommitObserver* observer); + + // Set this if you want commit to perform commit time rename. Will request + // that the client renames all commited entries, prepending this string. + void SetCommitTimeRename(std::string prepend); + + // Generic versions of AddUpdate functions. Tests using these function should + // compile for both the int64 and string id based versions of the server. + // The SyncEntity returned is only valid until the Sync is completed + // (e.g. with SyncShare.) It allows to add further entity properties before + // sync, using SetLastXXX() methods and/or GetMutableLastUpdate(). + sync_pb::SyncEntity* AddUpdateDirectory(syncable::Id id, + syncable::Id parent_id, + std::string name, + int64 version, + int64 sync_ts); + sync_pb::SyncEntity* AddUpdateBookmark(syncable::Id id, + syncable::Id parent_id, + std::string name, + int64 version, + int64 sync_ts); + // Versions of the AddUpdate functions that accept integer IDs. + sync_pb::SyncEntity* AddUpdateDirectory(int id, + int parent_id, + std::string name, + int64 version, + int64 sync_ts); + sync_pb::SyncEntity* AddUpdateBookmark(int id, + int parent_id, + std::string name, + int64 version, + int64 sync_ts); + // New protocol versions of the AddUpdate functions. + sync_pb::SyncEntity* AddUpdateDirectory(std::string id, + std::string parent_id, + std::string name, + int64 version, + int64 sync_ts); + sync_pb::SyncEntity* AddUpdateBookmark(std::string id, + std::string parent_id, + std::string name, + int64 version, + int64 sync_ts); + + // Find the last commit sent by the client, and replay it for the next get + // updates command. This can be used to simulate the GetUpdates that happens + // immediately after a successful commit. + sync_pb::SyncEntity* AddUpdateFromLastCommit(); + + // Add a deleted item. Deletion records typically contain no + // additional information beyond the deletion, and no specifics. + // The server may send the originator fields. + void AddUpdateTombstone(const syncable::Id& id); + + void SetLastUpdateDeleted(); + void SetLastUpdateServerTag(const std::string& tag); + void SetLastUpdateClientTag(const std::string& tag); + void SetLastUpdateOriginatorFields(const std::string& client_id, + const std::string& entry_id); + void SetLastUpdatePosition(int64 position_in_parent); + void SetNewTimestamp(int ts); + void SetChangesRemaining(int64 count); + + // Add a new batch of updates after the current one. Allows multiple + // GetUpdates responses to be buffered up, since the syncer may + // issue multiple requests during a sync cycle. + void NextUpdateBatch(); + + // For AUTHENTICATE responses. + void SetAuthenticationResponseInfo(const std::string& valid_auth_token, + const std::string& user_display_name, + const std::string& user_display_email, + const std::string& user_obfuscated_id); + + void FailNextPostBufferToPathCall() { fail_next_postbuffer_ = true; } + + void SetClearUserDataResponseStatus( + sync_pb::ClientToServerResponse::ErrorType errortype); + + // A visitor class to allow a test to change some monitoring state atomically + // with the action of overriding the response codes sent back to the Syncer + // (for example, so you can say "ThrottleNextRequest, and assert no more + // requests are made once throttling is in effect" in one step. + class ResponseCodeOverrideRequestor { + public: + // Called with response_code_override_lock_ acquired. + virtual void OnOverrideComplete() = 0; + + protected: + virtual ~ResponseCodeOverrideRequestor() {} + }; + void ThrottleNextRequest(ResponseCodeOverrideRequestor* visitor); + void FailWithAuthInvalid(ResponseCodeOverrideRequestor* visitor); + void StopFailingWithAuthInvalid(ResponseCodeOverrideRequestor* visitor); + void FailNonPeriodicGetUpdates() { fail_non_periodic_get_updates_ = true; } + + // Simple inspectors. + bool client_stuck() const { return client_stuck_; } + + sync_pb::ClientCommand* GetNextClientCommand(); + + const std::vector<syncable::Id>& committed_ids() const { + return committed_ids_; + } + const std::vector<sync_pb::CommitMessage*>& commit_messages() const { + return commit_messages_.get(); + } + const std::vector<sync_pb::CommitResponse*>& commit_responses() const { + return commit_responses_.get(); + } + // Retrieve the last sent commit message. + const sync_pb::CommitMessage& last_sent_commit() const; + + // Retrieve the last returned commit response. + const sync_pb::CommitResponse& last_commit_response() const; + + // Retrieve the last request submitted to the server (regardless of type). + const sync_pb::ClientToServerMessage& last_request() const { + return last_request_; + } + + void set_conflict_all_commits(bool value) { + conflict_all_commits_ = value; + } + void set_next_new_id(int value) { + next_new_id_ = value; + } + void set_conflict_n_commits(int value) { + conflict_n_commits_ = value; + } + + void set_use_legacy_bookmarks_protocol(bool value) { + use_legacy_bookmarks_protocol_ = value; + } + + void set_store_birthday(std::string new_birthday) { + // Multiple threads can set store_birthday_ in our tests, need to lock it to + // ensure atomic read/writes and avoid race conditions. + base::AutoLock lock(store_birthday_lock_); + store_birthday_ = new_birthday; + } + + // Retrieve the number of GetUpdates requests that the mock server has + // seen since the last time this function was called. Can be used to + // verify that a GetUpdates actually did or did not happen after running + // the syncer. + int GetAndClearNumGetUpdatesRequests() { + int result = num_get_updates_requests_; + num_get_updates_requests_ = 0; + return result; + } + + // Expect that GetUpdates will request exactly the types indicated in + // the bitset. + void ExpectGetUpdatesRequestTypes( + std::bitset<syncable::MODEL_TYPE_COUNT> expected_filter) { + expected_filter_ = expected_filter; + } + + void ExpectGetUpdatesRequestPayloads( + const syncable::ModelTypePayloadMap& payloads) { + expected_payloads_ = payloads; + } + + void SetServerReachable(); + + void SetServerNotReachable(); + + // Return by copy to be thread-safe. + const std::string store_birthday() { + base::AutoLock lock(store_birthday_lock_); + return store_birthday_; + } + + // Locate the most recent update message for purpose of alteration. + sync_pb::SyncEntity* GetMutableLastUpdate(); + + private: + sync_pb::SyncEntity* AddUpdateFull(syncable::Id id, syncable::Id parentid, + std::string name, int64 version, + int64 sync_ts, + bool is_dir); + sync_pb::SyncEntity* AddUpdateFull(std::string id, + std::string parentid, std::string name, + int64 version, int64 sync_ts, + bool is_dir); + // Functions to handle the various types of server request. + void ProcessGetUpdates(sync_pb::ClientToServerMessage* csm, + sync_pb::ClientToServerResponse* response); + void ProcessAuthenticate(sync_pb::ClientToServerMessage* csm, + sync_pb::ClientToServerResponse* response, + const std::string& auth_token); + void ProcessCommit(sync_pb::ClientToServerMessage* csm, + sync_pb::ClientToServerResponse* response_buffer); + void ProcessClearData(sync_pb::ClientToServerMessage* csm, + sync_pb::ClientToServerResponse* response); + void AddDefaultBookmarkData(sync_pb::SyncEntity* entity, bool is_folder); + + // Determine if one entry in a commit should be rejected with a conflict. + bool ShouldConflictThisCommit(); + + // Generate a numeric position_in_parent value. We use a global counter + // that only decreases; this simulates new objects always being added to the + // front of the ordering. + int64 GeneratePositionInParent() { + return next_position_in_parent_--; + } + + // Get a mutable update response which will eventually be returned to the + // client. + sync_pb::GetUpdatesResponse* GetUpdateResponse(); + void ApplyToken(); + + // Determine whether an progress marker array (like that sent in + // GetUpdates.from_progress_marker) indicates that a particular ModelType + // should be included. + bool IsModelTypePresentInSpecifics( + const google::protobuf::RepeatedPtrField< + sync_pb::DataTypeProgressMarker>& filter, + syncable::ModelType value); + + sync_pb::DataTypeProgressMarker const* GetProgressMarkerForType( + const google::protobuf::RepeatedPtrField< + sync_pb::DataTypeProgressMarker>& filter, + syncable::ModelType value); + + // All IDs that have been committed. + std::vector<syncable::Id> committed_ids_; + + // Control of when/if we return conflicts. + bool conflict_all_commits_; + int conflict_n_commits_; + + // Commit messages we've sent, and responses we've returned. + ScopedVector<sync_pb::CommitMessage> commit_messages_; + ScopedVector<sync_pb::CommitResponse> commit_responses_; + + // The next id the mock will return to a commit. + int next_new_id_; + + // The store birthday we send to the client. + std::string store_birthday_; + base::Lock store_birthday_lock_; + bool store_birthday_sent_; + bool client_stuck_; + std::string commit_time_rename_prepended_string_; + + // Fail on the next call to PostBufferToPath(). + bool fail_next_postbuffer_; + + // Our directory. + syncable::DirectoryManager* directory_manager_; + std::string directory_name_; + + // The updates we'll return to the next request. + std::list<sync_pb::GetUpdatesResponse> update_queue_; + scoped_ptr<Callback0::Type> mid_commit_callback_; + MidCommitObserver* mid_commit_observer_; + + // The clear data response we'll return in the next response + sync_pb::ClientToServerResponse::ErrorType + clear_user_data_response_errortype_; + + // The AUTHENTICATE response we'll return for auth requests. + sync_pb::AuthenticateResponse auth_response_; + // What we use to determine if we should return SUCCESS or BAD_AUTH_TOKEN. + std::string valid_auth_token_; + + // Whether we are faking a server mandating clients to throttle requests. + // Protected by |response_code_override_lock_|. + bool throttling_; + + // Whether we are failing all requests by returning + // ClientToServerResponse::AUTH_INVALID. + // Protected by |response_code_override_lock_|. + bool fail_with_auth_invalid_; + + base::Lock response_code_override_lock_; + + // True if we are only accepting GetUpdatesCallerInfo::PERIODIC requests. + bool fail_non_periodic_get_updates_; + + scoped_ptr<sync_pb::ClientCommand> client_command_; + + // The next value to use for the position_in_parent property. + int64 next_position_in_parent_; + + // The default is to use the newer sync_pb::BookmarkSpecifics-style protocol. + // If this option is set to true, then the MockConnectionManager will + // use the older sync_pb::SyncEntity_BookmarkData-style protocol. + bool use_legacy_bookmarks_protocol_; + + std::bitset<syncable::MODEL_TYPE_COUNT> expected_filter_; + + syncable::ModelTypePayloadMap expected_payloads_; + + int num_get_updates_requests_; + + std::string next_token_; + + sync_pb::ClientToServerMessage last_request_; + + DISALLOW_COPY_AND_ASSIGN(MockConnectionManager); +}; + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_MOCK_CONNECTION_MANAGER_H_ diff --git a/chrome/browser/sync/test/engine/mock_gaia_authenticator.cc b/chrome/browser/sync/test/engine/mock_gaia_authenticator.cc new file mode 100644 index 0000000..acd817c --- /dev/null +++ b/chrome/browser/sync/test/engine/mock_gaia_authenticator.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2009 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. +// +// Use MockGaiaAuthenticator to test your application by faking a login session. +// This mock object should be initialized with the response you expect it to +// return, and then can be used in exactly the same way as the real +// GaiaAuthenticator. + +#include "chrome/browser/sync/test/engine/mock_gaia_authenticator.h" + +using std::string; + +namespace browser_sync { + +MockGaiaAuthenticator::MockGaiaAuthenticator(const char* user_agent, + const char* service_id, + const char* gaia_url) : + should_save_credentials_(false), current_user_("") { + // This discards user_agent, service_id, gaia_url since the mock object + // doesn't care about them. +} + +MockGaiaAuthenticator::~MockGaiaAuthenticator() {} + +// Add a mock user to internal list of users. +void MockGaiaAuthenticator::AddMockUser(MockUser mock_user) { + mock_credentials_[mock_user.email] = mock_user; +} + +// A convenience method to add a mock user to internal list of users. +void MockGaiaAuthenticator::AddMockUser(string email, string passwd, + string auth_token, string lsid, + string sid, + enum gaia::AuthenticationError + auth_error, string error_url, + string captcha_token, + string captcha_url) { + MockUser mock_user; + mock_user.email = email; + mock_user.passwd = passwd; + mock_user.auth_token = auth_token; + mock_user.lsid = lsid; + mock_user.sid = sid; + mock_user.auth_error = auth_error; + mock_user.error_url = error_url; + mock_user.captcha_token = captcha_token; + mock_user.captcha_url = captcha_url; + AddMockUser(mock_user); +} + +// A convenience method to add a mock user to internal list of users. +void MockGaiaAuthenticator::AddMockUser(string email, string passwd, + string auth_token, string lsid, + string sid, + enum gaia::AuthenticationError + auth_error) { + MockUser mock_user; + mock_user.email = email; + mock_user.passwd = passwd; + mock_user.auth_token = auth_token; + mock_user.lsid = lsid; + mock_user.sid = sid; + mock_user.auth_error = auth_error; + AddMockUser(mock_user); +} + +void MockGaiaAuthenticator::RemoveMockUser(const char* email) { + mock_credentials_.erase(email); +} + +void MockGaiaAuthenticator::RemoveAllMockUsers() { + mock_credentials_.clear(); +} + +bool MockGaiaAuthenticator::Authenticate() { + if (!should_save_credentials_) { + ResetCredentials(); + return false; + } + return Authenticate(mock_credentials_[current_user_].email.c_str(), + mock_credentials_[current_user_].passwd.c_str(), true); +} + +bool MockGaiaAuthenticator::Authenticate(const char* email, + const char* passwd, + bool should_save_credentials) { + // Simply assign value to field; the value is read by the accessors when + // reading. + should_save_credentials_ = should_save_credentials; + + // Check if we already know about this mock user. + if (mock_credentials_.find(email) == mock_credentials_.end()) { + current_user_ = ""; + return false; + } + + // If found, keep the current logged-in user available for token requests. + current_user_ = email; + + // Finding a user does not necessarily imply that the user was logged in OK. + // Therefore also check if the AuthenticationError is None. + return (mock_credentials_[current_user_].auth_error == gaia::None); +} + +// Remove any stored knowledge about the currently logged-in user, but keep +// details of mock users. +void MockGaiaAuthenticator::ResetCredentials() { + current_user_ = ""; +} + +std::string MockGaiaAuthenticator::email() { + return (current_user_.empty() || !should_save_credentials_) ? "" : + mock_credentials_[current_user_].email; +} + +std::string MockGaiaAuthenticator::auth_token() { + return (current_user_.empty()) ? "" : + mock_credentials_[current_user_].auth_token; +} + +std::string MockGaiaAuthenticator::sid() { + return (current_user_.empty()) ? "" : + mock_credentials_[current_user_].sid; +} + +std::string MockGaiaAuthenticator::lsid() { + return (current_user_.empty()) ? "" : + mock_credentials_[current_user_].lsid; +} + +gaia::AuthenticationError MockGaiaAuthenticator::auth_error() { + return (current_user_.empty()) ? gaia::CredentialsNotSet : + mock_credentials_[current_user_].auth_error; +} + +std::string MockGaiaAuthenticator::auth_error_url() { + return (current_user_.empty()) ? "" : + mock_credentials_[current_user_].error_url; +} + +std::string MockGaiaAuthenticator::captcha_token() { + return (current_user_.empty()) ? "" : + mock_credentials_[current_user_].captcha_token; +} + +std::string MockGaiaAuthenticator::captcha_url() { + return (current_user_.empty()) ? "" : + mock_credentials_[current_user_].captcha_url; +} + +} // namespace browser_sync diff --git a/chrome/browser/sync/test/engine/mock_gaia_authenticator.h b/chrome/browser/sync/test/engine/mock_gaia_authenticator.h new file mode 100644 index 0000000..e9f3251 --- /dev/null +++ b/chrome/browser/sync/test/engine/mock_gaia_authenticator.h @@ -0,0 +1,117 @@ +// Copyright (c) 2009 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. +// +// Use MockGaiaAuthenticator to test your application by faking a login session. +// This mock object should be initialized with the response you expect it to +// return for multiple users, and then can be used in exactly the same way +// as the real GaiaAuthenticator. +// +// Sample usage: +// MockGaiaAuthenticator mock_gaia_auth("User-Agent", SYNC_SERVICE_NAME, +// "any random string"); +// mock_gaia_auth.AddMockUser("email", "password", "authtoken", "lsid", "sid", +// AuthenticationError); +// mock_gaia_auth.AddMockUser("email2", "password2", "authtoken2", "lsid2", +// "sid2", AuthenticationError, error_url, +// "captcha_token", "captcha_url"); +// if (gaia_auth.Authenticate("email", "passwd")) { +// // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(), +// // or gaia_auth.lsid() +// } + +#ifndef CHROME_BROWSER_SYNC_TEST_ENGINE_MOCK_GAIA_AUTHENTICATOR_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_MOCK_GAIA_AUTHENTICATOR_H_ +#pragma once + +#include <map> +#include <string> + +#include "base/port.h" + +#include "base/basictypes.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" + +namespace browser_sync { + +// A struct used internally for storing a user's credentials. You can either +// create one yourself, or use the convenience methods to have the +// MockGaiaAuthenticator create one for you. +typedef struct { + std::string email; + std::string passwd; + std::string auth_token; + std::string sid; + std::string lsid; + gaia::AuthenticationError auth_error; + std::string captcha_token; + std::string captcha_url; + std::string error_url; +} MockUser; + +// MockGaiaAuthenticator can be used to fake Gaia authentication without +// actually making a network connection. For details about the methods shared +// with GaiaAuthenticator, see GaiaAuthenticator in gaia_auth.h. Only methods +// that are unique to MockGaiaAuthenticator are documented in this file. +class MockGaiaAuthenticator { + public: + MockGaiaAuthenticator(const char* user_agent, const char* service_id, + const char* gaia_url); + ~MockGaiaAuthenticator(); + + // Add a mock user; takes a struct. You can populate any or all fields when + // adding a user. The email field is required, all others optional. + void AddMockUser(MockUser mock_user); + + // A convenience method that makes it easy to create new mock users in a + // single method call. Includes all parameters. + void AddMockUser(std::string email, std::string passwd, + std::string auth_token, + std::string lsid, std::string sid, + gaia::AuthenticationError auth_error, + std::string error_url, std::string captcha_token, + std::string captcha_url); + + // A convenience method that makes it easy to create new mock users in a + // single method call. Includes only the most common parameters. See overload + // if you want to pass all parameters. + void AddMockUser(std::string email, std::string passwd, + std::string auth_token, + std::string lsid, std::string sid, + enum gaia::AuthenticationError auth_error); + + // Removes a mock user from the current list of added users. + void RemoveMockUser(const char* email); + + // Removes all mock users from the current list of added users. + void RemoveAllMockUsers(); + + // See GaiaAuthenticator::Authenticate() + bool Authenticate(); + + // See GaiaAuthenticator::Authenticate(...) + bool Authenticate(const char* user_name, const char* password, + bool should_save_credentials = false); + + // See GaiaAuthenticator::Authenticate(...) + void ResetCredentials(); + + // Accessors follow. + std::string email(); + std::string auth_token(); + std::string sid(); + std::string lsid(); + gaia::AuthenticationError auth_error(); + std::string auth_error_url(); + std::string captcha_token(); + std::string captcha_url(); + + private: + bool should_save_credentials_; + std::map<std::string, MockUser> mock_credentials_; + std::string current_user_; +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_MOCK_GAIA_AUTHENTICATOR_H_ diff --git a/chrome/browser/sync/test/engine/mock_gaia_authenticator_unittest.cc b/chrome/browser/sync/test/engine/mock_gaia_authenticator_unittest.cc new file mode 100644 index 0000000..a3571ba --- /dev/null +++ b/chrome/browser/sync/test/engine/mock_gaia_authenticator_unittest.cc @@ -0,0 +1,158 @@ +// Copyright (c) 2009 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. +// +// Unit tests for MockGaiaAuthenticator. + +#include "base/basictypes.h" +#include "base/port.h" +#include "chrome/browser/sync/protocol/service_constants.h" +#include "chrome/browser/sync/test/engine/mock_gaia_authenticator.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Test if authentication succeeds for a mock user added earlier. +TEST(MockGaiaAuthenticatorTest, TestAuthenticationSuccess) { + browser_sync::MockGaiaAuthenticator + mock_gaia_auth("User-Agent", SYNC_SERVICE_NAME, + "some random url"); + + // Initialize a mock user, and add to mock authenticator. + browser_sync::MockUser mock_user; + mock_user.email = "test"; + mock_user.passwd = "passwd"; + mock_user.auth_token = "SomeAuthToken"; + mock_user.lsid = "SomeLSID"; + mock_user.sid = "SomeSID"; + mock_user.auth_error = gaia::None; + mock_gaia_auth.AddMockUser(mock_user); + + // Assert away ... + ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd")); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), "SomeAuthToken"); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), "SomeSID"); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), "SomeLSID"); +} + +// Test if authentication fails for a mock user that was never added. +TEST(MockGaiaAuthenticatorTest, TestAuthenticationFailure) { + browser_sync::MockGaiaAuthenticator + mock_gaia_auth("User-Agent", SYNC_SERVICE_NAME, + "some random url"); + + // At this point, in real code, we would be adding mock users to our mock + // object. However, in this unittest, we exercise the path where this step is + // missing, and assert that the outcome is still consistent with that of the + // real GaiaAuthenticator. + + // Assert away ... + ASSERT_FALSE(mock_gaia_auth.Authenticate("test", "passwd")); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), ""); +} + +// Test if authentication fails after a mock user is removed. +TEST(MockGaiaAuthenticatorTest, TestRemoveMockUser) { + // Instantiate authenticator. + browser_sync::MockGaiaAuthenticator + mock_gaia_auth("User-Agent", SYNC_SERVICE_NAME, + "some random url"); + + // Add our mock user + mock_gaia_auth.AddMockUser("test", "passwd", "SomeAuthToken", "SomeLSID", + "SomeSID", gaia::None); + + // Make sure authentication succeeds. + ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd")); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), "SomeAuthToken"); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), "SomeSID"); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), "SomeLSID"); + + // Remove the just-added user from our list. + mock_gaia_auth.RemoveMockUser("test"); + + // ... and authentication should fail. + ASSERT_FALSE(mock_gaia_auth.Authenticate("test", "passwd")); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), ""); +} + +// Test if authentication fails after all mock users are removed. +TEST(MockGaiaAuthenticatorTest, TestRemoveAllMockUsers) { + // Instantiate authenticator. + browser_sync::MockGaiaAuthenticator + mock_gaia_auth("User-Agent", SYNC_SERVICE_NAME, + "some random url"); + + // Add our sample mock user. + mock_gaia_auth.AddMockUser("test", "passwd", "SomeAuthToken", "SomeLSID", + "SomeSID", gaia::None); + + // Make sure authentication succeeds + ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd")); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), "SomeAuthToken"); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), "SomeSID"); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), "SomeLSID"); + + // Now remove all mock users. + mock_gaia_auth.RemoveAllMockUsers(); + + // And confirm that authentication fails. + ASSERT_FALSE(mock_gaia_auth.Authenticate("test", "passwd")); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), ""); +} + +// Test authentication with saved credentials. +TEST(MockGaiaAuthenticatorTest, TestSavedCredentials) { + // Instantiate authenticator. + browser_sync::MockGaiaAuthenticator + mock_gaia_auth("User-Agent", SYNC_SERVICE_NAME, + "some random url"); + + // Add our sample mock user. + mock_gaia_auth.AddMockUser("test", "passwd", "SomeAuthToken", "SomeLSID", + "SomeSID", gaia::None); + + // Ask to save credentials. + ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd", true)); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), "SomeAuthToken"); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), "SomeSID"); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), "SomeLSID"); + + // Now make a call that uses saved credentials, and assert that we get the + // same tokens back. + ASSERT_TRUE(mock_gaia_auth.Authenticate()); + ASSERT_STREQ(mock_gaia_auth.email().c_str(), "test"); + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), "SomeAuthToken"); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), "SomeSID"); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), "SomeLSID"); + + // Now clear the saved credentials by toggling the flag while authenticating. + ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd", false)); + + // Test if saved credentials have been cleared. + ASSERT_STREQ(mock_gaia_auth.email().c_str(), ""); + + // Assert that current authentication session still succeeds (we only asked + // not to save it for future requests.) + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), "SomeAuthToken"); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), "SomeSID"); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), "SomeLSID"); + + // Now try to use saved credentials: + ASSERT_STREQ(mock_gaia_auth.email().c_str(), ""); + ASSERT_FALSE(mock_gaia_auth.Authenticate()); + + // And assert that any future requests that rely on saved credentials fail. + ASSERT_STREQ(mock_gaia_auth.auth_token().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.sid().c_str(), ""); + ASSERT_STREQ(mock_gaia_auth.lsid().c_str(), ""); +} + +} // namespace diff --git a/chrome/browser/sync/test/engine/proto_extension_validator.h b/chrome/browser/sync/test/engine/proto_extension_validator.h new file mode 100644 index 0000000..747bf3d --- /dev/null +++ b/chrome/browser/sync/test/engine/proto_extension_validator.h @@ -0,0 +1,55 @@ +// Copyright (c) 2010 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. + +// A test utility that makes it easy to assert the exact presence of +// protobuf extensions in an extensible message. Example code: +// +// sync_pb::EntitySpecifics value; // Set up a test value. +// value.MutableExtension(sync_pb::bookmark); +// +// ProtoExtensionValidator<sync_pb::EntitySpecifics> good_expectation(value); +// good_expectation.ExpectHasExtension(sync_pb::bookmark); +// good_expectation.ExpectHasNoOtherFieldsOrExtensions(); +// +// ProtoExtensionValidator<sync_pb::EntitySpecifics> bad_expectation(value); +// bad_expectation.ExpectHasExtension(sync_pb::preference); // Fails, no pref +// bad_expectation.ExpectHasNoOtherFieldsOrExtensions(); // Fails, bookmark + +#ifndef CHROME_BROWSER_SYNC_TEST_ENGINE_PROTO_EXTENSION_VALIDATOR_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_PROTO_EXTENSION_VALIDATOR_H_ +#pragma once + +#include "base/string_util.h" +#include "chrome/browser/sync/test/engine/syncer_command_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace browser_sync { + +template<typename MessageType> +class ProtoExtensionValidator { + public: + explicit ProtoExtensionValidator(const MessageType& proto) + : proto_(proto) { + } + template<typename ExtensionTokenType> + void ExpectHasExtension(ExtensionTokenType token) { + EXPECT_TRUE(proto_.HasExtension(token)) + << "Proto failed to contain expected extension"; + proto_.ClearExtension(token); + EXPECT_FALSE(proto_.HasExtension(token)); + } + void ExpectNoOtherFieldsOrExtensions() { + EXPECT_EQ(MessageType::default_instance().SerializeAsString(), + proto_.SerializeAsString()) + << "Proto contained additional unexpected extensions."; + } + + private: + MessageType proto_; + DISALLOW_COPY_AND_ASSIGN(ProtoExtensionValidator); +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_PROTO_EXTENSION_VALIDATOR_H_ diff --git a/chrome/browser/sync/test/engine/syncer_command_test.h b/chrome/browser/sync/test/engine/syncer_command_test.h new file mode 100644 index 0000000..e153be23 --- /dev/null +++ b/chrome/browser/sync/test/engine/syncer_command_test.h @@ -0,0 +1,170 @@ +// Copyright (c) 2011 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_ENGINE_SYNCER_COMMAND_TEST_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_SYNCER_COMMAND_TEST_H_ +#pragma once + +#include <algorithm> +#include <string> +#include <vector> + +#include "base/compiler_specific.h" +#include "chrome/browser/sync/engine/model_safe_worker.h" +#include "chrome/browser/sync/sessions/sync_session.h" +#include "chrome/browser/sync/sessions/sync_session_context.h" +#include "chrome/browser/sync/test/engine/mock_connection_manager.h" +#include "chrome/browser/sync/test/engine/test_directory_setter_upper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace browser_sync { + +// A test fixture that simplifies writing unit tests for individual +// SyncerCommands, providing convenient access to a test directory +// and a syncer session. +template<typename T> +class SyncerCommandTestWithParam : public testing::TestWithParam<T>, + public sessions::SyncSession::Delegate, + public ModelSafeWorkerRegistrar { + public: + enum UseMockDirectory { + USE_MOCK_DIRECTORY + }; + + // SyncSession::Delegate implementation. + virtual void OnSilencedUntil( + const base::TimeTicks& silenced_until) OVERRIDE { + FAIL() << "Should not get silenced."; + } + virtual bool IsSyncingCurrentlySilenced() OVERRIDE { + ADD_FAILURE() << "No requests for silenced state should be made."; + return false; + } + virtual void OnReceivedLongPollIntervalUpdate( + const base::TimeDelta& new_interval) OVERRIDE { + FAIL() << "Should not get poll interval update."; + } + virtual void OnReceivedShortPollIntervalUpdate( + const base::TimeDelta& new_interval) OVERRIDE { + FAIL() << "Should not get poll interval update."; + } + virtual void OnReceivedSessionsCommitDelay( + const base::TimeDelta& new_delay) OVERRIDE { + FAIL() << "Should not get sessions commit delay."; + } + virtual void OnShouldStopSyncingPermanently() OVERRIDE { + FAIL() << "Shouldn't be called."; + } + virtual void OnSyncProtocolError( + const sessions::SyncSessionSnapshot& session) OVERRIDE { + FAIL() << "Shouldn't be called."; + } + + // ModelSafeWorkerRegistrar implementation. + virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) OVERRIDE { + std::vector<scoped_refptr<ModelSafeWorker> >::iterator it; + for (it = workers_.begin(); it != workers_.end(); ++it) + out->push_back(*it); + } + virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) OVERRIDE { + ModelSafeRoutingInfo copy(routing_info_); + out->swap(copy); + } + + protected: + SyncerCommandTestWithParam() : syncdb_(new TestDirectorySetterUpper()) {} + + explicit SyncerCommandTestWithParam(UseMockDirectory use_mock) + : syncdb_(new MockDirectorySetterUpper()) {} + + virtual ~SyncerCommandTestWithParam() {} + virtual void SetUp() { + syncdb_->SetUp(); + ResetContext(); + } + virtual void TearDown() { + syncdb_->TearDown(); + } + + TestDirectorySetterUpper* syncdb() { return syncdb_.get(); } + sessions::SyncSessionContext* context() const { return context_.get(); } + sessions::SyncSession::Delegate* delegate() { return this; } + ModelSafeWorkerRegistrar* registrar() { return this; } + + // Lazily create a session requesting all datatypes with no payload. + sessions::SyncSession* session() { + syncable::ModelTypePayloadMap types = + syncable::ModelTypePayloadMapFromRoutingInfo(routing_info_, + std::string()); + return session(sessions::SyncSourceInfo(types)); + } + + // Create a session with the provided source. + sessions::SyncSession* session(const sessions::SyncSourceInfo& source) { + if (!session_.get()) { + std::vector<ModelSafeWorker*> workers; + GetWorkers(&workers); + session_.reset(new sessions::SyncSession(context(), delegate(), source, + routing_info_, workers)); + } + return session_.get(); + } + + void ClearSession() { + session_.reset(); + } + + void ResetContext() { + context_.reset(new sessions::SyncSessionContext( + mock_server_.get(), syncdb_->manager(), registrar(), + std::vector<SyncEngineEventListener*>())); + context_->set_account_name(syncdb_->name()); + ClearSession(); + } + + // Install a MockServerConnection. Resets the context. By default, + // the context does not have a MockServerConnection attached. + void ConfigureMockServerConnection() { + mock_server_.reset( + new MockConnectionManager(syncdb_->manager(), syncdb_->name())); + ResetContext(); + } + + std::vector<scoped_refptr<ModelSafeWorker> >* workers() { + return &workers_; + } + + const ModelSafeRoutingInfo& routing_info() { return routing_info_; } + ModelSafeRoutingInfo* mutable_routing_info() { return &routing_info_; } + + MockConnectionManager* mock_server() { + return mock_server_.get(); + } + + private: + scoped_ptr<TestDirectorySetterUpper> syncdb_; + scoped_ptr<sessions::SyncSessionContext> context_; + scoped_ptr<MockConnectionManager> mock_server_; + scoped_ptr<sessions::SyncSession> session_; + std::vector<scoped_refptr<ModelSafeWorker> > workers_; + ModelSafeRoutingInfo routing_info_; + DISALLOW_COPY_AND_ASSIGN(SyncerCommandTestWithParam); +}; + +class SyncerCommandTest : public SyncerCommandTestWithParam<void*> {}; + +class MockDirectorySyncerCommandTest + : public SyncerCommandTestWithParam<void*> { + public: + MockDirectorySyncerCommandTest() + : SyncerCommandTestWithParam<void*>( + SyncerCommandTestWithParam<void*>::USE_MOCK_DIRECTORY) {} + MockDirectorySetterUpper::MockDirectory* mock_directory() { + return static_cast<MockDirectorySetterUpper*>(syncdb())->directory(); + } +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_SYNCER_COMMAND_TEST_H_ diff --git a/chrome/browser/sync/test/engine/test_directory_setter_upper.cc b/chrome/browser/sync/test/engine/test_directory_setter_upper.cc new file mode 100644 index 0000000..44eeb19 --- /dev/null +++ b/chrome/browser/sync/test/engine/test_directory_setter_upper.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011 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/engine/test_directory_setter_upper.h" + +#include "base/compiler_specific.h" +#include "base/file_util.h" +#include "base/string_util.h" +#include "base/tracked.h" +#include "chrome/browser/sync/syncable/directory_manager.h" +#include "chrome/browser/sync/syncable/syncable.h" +#include "testing/gtest/include/gtest/gtest.h" + +using syncable::DirectoryManager; +using syncable::ReadTransaction; +using syncable::ScopedDirLookup; + +namespace browser_sync { + +TestDirectorySetterUpper::TestDirectorySetterUpper() : name_("Test") {} +TestDirectorySetterUpper::TestDirectorySetterUpper(const std::string& name) + : name_(name) {} + +TestDirectorySetterUpper::~TestDirectorySetterUpper() {} + +void TestDirectorySetterUpper::Init() { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + reset_directory_manager(new DirectoryManager(temp_dir_.path())); + // There shouldn't be any existing database in the newly-created + // temp dir. + ASSERT_FALSE(file_util::PathExists(manager_->GetSyncDataDatabasePath())); +} + +void TestDirectorySetterUpper::reset_directory_manager(DirectoryManager* d) { + manager_.reset(d); +} + +void TestDirectorySetterUpper::SetUp() { + Init(); + ASSERT_TRUE(manager()->Open(name(), &delegate_)); +} + +void TestDirectorySetterUpper::TearDown() { + if (!manager()) + return; + + { + // A small scope so we don't have the dir open when we close it and reset + // the DirectoryManager below. + ScopedDirLookup dir(manager(), name()); + CHECK(dir.good()) << "Bad directory during tear down check"; + RunInvariantCheck(dir); + dir->SaveChanges(); + RunInvariantCheck(dir); + dir->SaveChanges(); + } + + manager()->FinalSaveChangesForAll(); + manager()->Close(name()); + manager_.reset(); + ASSERT_TRUE(temp_dir_.Delete()); +} + +void TestDirectorySetterUpper::RunInvariantCheck(const ScopedDirLookup& dir) { + { + // Check invariants for in-memory items. + ReadTransaction trans(FROM_HERE, dir); + dir->CheckTreeInvariants(&trans, false); + } + { + // Check invariants for all items. + ReadTransaction trans(FROM_HERE, dir); + dir->CheckTreeInvariants(&trans, true); + } +} + +void ManuallyOpenedTestDirectorySetterUpper::SetUp() { + Init(); +} + +void ManuallyOpenedTestDirectorySetterUpper::Open() { + ASSERT_TRUE(manager()->Open(name(), &delegate_)); + was_opened_ = true; +} + +void ManuallyOpenedTestDirectorySetterUpper::TearDown() { + if (was_opened_) { + TestDirectorySetterUpper::TearDown(); + } +} + +TriggeredOpenTestDirectorySetterUpper::TriggeredOpenTestDirectorySetterUpper( + const std::string& name) + : TestDirectorySetterUpper(name) { +} + +void TriggeredOpenTestDirectorySetterUpper::SetUp() { + Init(); +} + +void TriggeredOpenTestDirectorySetterUpper::TearDown() { + DirectoryManager::DirNames names; + manager()->GetOpenDirectories(&names); + if (!names.empty()) { + ASSERT_EQ(1U, names.size()); + ASSERT_EQ(name(), names[0]); + TestDirectorySetterUpper::TearDown(); + } +} + +MockDirectorySetterUpper::MockDirectory::MockDirectory( + const std::string& name) { + InitKernel(name, &delegate_); +} + +MockDirectorySetterUpper::MockDirectory::~MockDirectory() {} + +MockDirectorySetterUpper::Manager::Manager( + const FilePath& root_path, syncable::Directory* dir) : + syncable::DirectoryManager(root_path) { + managed_directory_ = dir; +} + +MockDirectorySetterUpper::MockDirectorySetterUpper() + : directory_(new MockDirectory(name())) { +} + +MockDirectorySetterUpper::~MockDirectorySetterUpper() {} + +void MockDirectorySetterUpper::SetUp() { + reset_directory_manager(new Manager(FilePath(), directory_.get())); +} + +void MockDirectorySetterUpper::TearDown() { + // Nothing to do here. +} + +} // namespace browser_sync diff --git a/chrome/browser/sync/test/engine/test_directory_setter_upper.h b/chrome/browser/sync/test/engine/test_directory_setter_upper.h new file mode 100644 index 0000000..32af713 --- /dev/null +++ b/chrome/browser/sync/test/engine/test_directory_setter_upper.h @@ -0,0 +1,144 @@ +// Copyright (c) 2011 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. +// +// A handy class that takes care of setting up and destroying a +// syncable::Directory instance for unit tests that require one. +// +// The expected usage is to make this a component of your test fixture: +// +// class AwesomenessTest : public testing::Test { +// public: +// virtual void SetUp() { +// metadb_.SetUp(); +// } +// virtual void TearDown() { +// metadb_.TearDown(); +// } +// protected: +// TestDirectorySetterUpper metadb_; +// }; +// +// Then, in your tests, get at the directory like so: +// +// TEST_F(AwesomenessTest, IsMaximal) { +// ScopedDirLookup dir(metadb_.manager(), metadb_.name()); +// ... now use |dir| to get at syncable::Entry objects ... +// } +// + +#ifndef CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_DIRECTORY_SETTER_UPPER_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_DIRECTORY_SETTER_UPPER_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/scoped_temp_dir.h" +#include "chrome/browser/sync/syncable/directory_manager.h" +#include "chrome/browser/sync/syncable/syncable.h" +#include "chrome/browser/sync/test/null_directory_change_delegate.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace syncable { +class DirectoryManager; +class ScopedDirLookup; +} // namespace syncable + +namespace browser_sync { + +class TestDirectorySetterUpper { + public: + TestDirectorySetterUpper(); + virtual ~TestDirectorySetterUpper(); + + // Create a DirectoryManager instance and use it to open the directory. + // Clears any existing database backing files that might exist on disk. + virtual void SetUp(); + + // Undo everything done by SetUp(): close the directory and delete the + // backing files. Before closing the directory, this will run the directory + // invariant checks and perform the SaveChanges action on the directory. + virtual void TearDown(); + + syncable::DirectoryManager* manager() const { return manager_.get(); } + const std::string& name() const { return name_; } + + protected: + // Subclasses may want to use a different directory name. + explicit TestDirectorySetterUpper(const std::string& name); + virtual void Init(); + void reset_directory_manager(syncable::DirectoryManager* d); + + syncable::NullDirectoryChangeDelegate delegate_; + + private: + void RunInvariantCheck(const syncable::ScopedDirLookup& dir); + + scoped_ptr<syncable::DirectoryManager> manager_; + const std::string name_; + ScopedTempDir temp_dir_; + + DISALLOW_COPY_AND_ASSIGN(TestDirectorySetterUpper); +}; + +// A variant of the above where SetUp does not actually open the directory. +// You must manually invoke Open(). This is useful if you are writing a test +// that depends on the DirectoryManager::OPENED event. +class ManuallyOpenedTestDirectorySetterUpper : public TestDirectorySetterUpper { + public: + ManuallyOpenedTestDirectorySetterUpper() : was_opened_(false) {} + virtual void SetUp(); + virtual void TearDown(); + void Open(); + private: + bool was_opened_; +}; + +// Use this flavor if you have a test that will trigger the opening event to +// happen automagically. It is careful on teardown to close only if needed. +class TriggeredOpenTestDirectorySetterUpper : public TestDirectorySetterUpper { + public: + // A triggered open is typically in response to a successful auth event just + // as in "real life". In this case, the name that will be used should be + // deterministically known at construction, and is passed in |name|. + explicit TriggeredOpenTestDirectorySetterUpper(const std::string& name); + virtual void SetUp(); + virtual void TearDown(); +}; + +// Use this when you don't want to test the whole stack down to the Directory +// level, as it installs a google mock Directory implementation. +class MockDirectorySetterUpper : public TestDirectorySetterUpper { + public: + class Manager : public syncable::DirectoryManager { + public: + Manager(const FilePath& root_path, syncable::Directory* dir); + virtual ~Manager() { managed_directory_ = NULL; } + }; + + class MockDirectory : public syncable::Directory { + public: + explicit MockDirectory(const std::string& name); + virtual ~MockDirectory(); + MOCK_METHOD1(PurgeEntriesWithTypeIn, void(const syncable::ModelTypeSet&)); + + private: + syncable::NullDirectoryChangeDelegate delegate_; + }; + + MockDirectorySetterUpper(); + virtual ~MockDirectorySetterUpper(); + + virtual void SetUp(); + virtual void TearDown(); + MockDirectory* directory() { return directory_.get(); } + + private: + scoped_ptr<MockDirectory> directory_; +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_DIRECTORY_SETTER_UPPER_H_ diff --git a/chrome/browser/sync/test/engine/test_id_factory.h b/chrome/browser/sync/test/engine/test_id_factory.h new file mode 100644 index 0000000..ca98353 --- /dev/null +++ b/chrome/browser/sync/test/engine/test_id_factory.h @@ -0,0 +1,73 @@ +// Copyright (c) 2009 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. +// +// A tool making it easier to create IDs for unit testing. + +#ifndef CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_ID_FACTORY_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_ID_FACTORY_H_ +#pragma once + +#include <string> + +#include "base/string_number_conversions.h" +#include "chrome/browser/sync/syncable/syncable_id.h" + +namespace browser_sync { + +class TestIdFactory { + public: + TestIdFactory() : next_value_(1337000) {} + ~TestIdFactory() {} + + // Get the root ID. + static syncable::Id root() { + return syncable::Id(); + } + + // Make an ID from a number. If the number is zero, return the root ID. + // If the number is positive, create a server ID based on the value. If + // the number is negative, create a local ID based on the value. This + // is deterministic, and [FromNumber(X) == FromNumber(Y)] iff [X == Y]. + static syncable::Id FromNumber(int64 value) { + if (value == 0) + return root(); + else if (value < 0) + return syncable::Id::CreateFromClientString(base::Int64ToString(value)); + else + return syncable::Id::CreateFromServerId(base::Int64ToString(value)); + } + + // Create a local ID from a name. + static syncable::Id MakeLocal(std::string name) { + return syncable::Id::CreateFromClientString(std::string("lient ") + name); + } + + // Create a server ID from a string name. + static syncable::Id MakeServer(std::string name) { + return syncable::Id::CreateFromServerId(std::string("erver ") + name); + } + + // Autogenerate a fresh local ID. + syncable::Id NewLocalId() { + return syncable::Id::CreateFromClientString( + std::string("_auto ") + base::IntToString(-next_value())); + } + + // Autogenerate a fresh server ID. + syncable::Id NewServerId() { + return syncable::Id::CreateFromServerId( + std::string("_auto ") + base::IntToString(next_value())); + } + + private: + int next_value() { + return next_value_++; + } + int next_value_; +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_ID_FACTORY_H_ + diff --git a/chrome/browser/sync/test/engine/test_syncable_utils.cc b/chrome/browser/sync/test/engine/test_syncable_utils.cc new file mode 100644 index 0000000..b76f6f7 --- /dev/null +++ b/chrome/browser/sync/test/engine/test_syncable_utils.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2011 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. + +// Utilities to verify the state of items in unit tests. + +#include "chrome/browser/sync/test/engine/test_syncable_utils.h" + +#include "chrome/browser/sync/syncable/syncable.h" + +using std::string; + +namespace syncable { + +int CountEntriesWithName(BaseTransaction* rtrans, + const syncable::Id& parent_id, + const string& name) { + Directory::ChildHandles child_handles; + rtrans->directory()->GetChildHandlesById(rtrans, parent_id, &child_handles); + if (child_handles.size() <= 0) { + return 0; + } + + int number_of_entries_with_name = 0; + for (Directory::ChildHandles::iterator i = child_handles.begin(); + i != child_handles.end(); ++i) { + Entry e(rtrans, GET_BY_HANDLE, *i); + CHECK(e.good()); + if (e.Get(NON_UNIQUE_NAME) == name) { + ++number_of_entries_with_name; + } + } + return number_of_entries_with_name; +} + +Id GetFirstEntryWithName(BaseTransaction* rtrans, + const syncable::Id& parent_id, + const string& name) { + Directory::ChildHandles child_handles; + rtrans->directory()->GetChildHandlesById(rtrans, parent_id, &child_handles); + + for (Directory::ChildHandles::iterator i = child_handles.begin(); + i != child_handles.end(); ++i) { + Entry e(rtrans, GET_BY_HANDLE, *i); + CHECK(e.good()); + if (e.Get(NON_UNIQUE_NAME) == name) { + return e.Get(ID); + } + } + + CHECK(false); + return Id(); +} + +Id GetOnlyEntryWithName(BaseTransaction* rtrans, + const syncable::Id& parent_id, + const string& name) { + CHECK(1 == CountEntriesWithName(rtrans, parent_id, name)); + return GetFirstEntryWithName(rtrans, parent_id, name); +} + +} // namespace syncable diff --git a/chrome/browser/sync/test/engine/test_syncable_utils.h b/chrome/browser/sync/test/engine/test_syncable_utils.h new file mode 100644 index 0000000..2919e84 --- /dev/null +++ b/chrome/browser/sync/test/engine/test_syncable_utils.h @@ -0,0 +1,41 @@ +// Copyright (c) 2009 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. +// +// Utilities that are useful in verifying the state of items in a +// syncable database. + +#ifndef CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_SYNCABLE_UTILS_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_SYNCABLE_UTILS_H_ +#pragma once + +#include <string> + +#include "chrome/browser/sync/syncable/syncable.h" + +namespace syncable { + +class BaseTransaction; +class Id; + +// Count the number of entries with a given name inside of a parent. +// Useful to check folder structure and for porting older tests that +// rely on uniqueness inside of folders. +int CountEntriesWithName(BaseTransaction* rtrans, + const syncable::Id& parent_id, + const std::string& name); + +// Get the first entry ID with name in a parent. The entry *must* exist. +Id GetFirstEntryWithName(BaseTransaction* rtrans, + const syncable::Id& parent_id, + const std::string& name); + +// Assert that there's only one entry by this name in this parent. +// Return the Id. +Id GetOnlyEntryWithName(BaseTransaction* rtrans, + const syncable::Id& parent_id, + const std::string& name); + +} // namespace syncable + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_SYNCABLE_UTILS_H_ diff --git a/chrome/browser/sync/test/engine/test_user_share.cc b/chrome/browser/sync/test/engine/test_user_share.cc new file mode 100644 index 0000000..6010d07 --- /dev/null +++ b/chrome/browser/sync/test/engine/test_user_share.cc @@ -0,0 +1,35 @@ +// Copyright (c) 2011 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/engine/test_user_share.h" + +#include "base/compiler_specific.h" + +namespace browser_sync { + +TestUserShare::TestUserShare() {} + +TestUserShare::~TestUserShare() { + CHECK(!user_share_.dir_manager.get()); +} + +void TestUserShare::SetUp() { + setter_upper_.SetUp(); + // HACK: We have two scoped_ptrs to the same object. But we make + // sure to release one in TearDown. + user_share_.dir_manager.reset(setter_upper_.manager()); + user_share_.name = setter_upper_.name(); +} + +void TestUserShare::TearDown() { + // Make sure we don't free the manager twice. + ignore_result(user_share_.dir_manager.release()); + setter_upper_.TearDown(); +} + +sync_api::UserShare* TestUserShare::user_share() { + return &user_share_; +} + +} // namespace browser_sync diff --git a/chrome/browser/sync/test/engine/test_user_share.h b/chrome/browser/sync/test/engine/test_user_share.h new file mode 100644 index 0000000..cd996ee --- /dev/null +++ b/chrome/browser/sync/test/engine/test_user_share.h @@ -0,0 +1,67 @@ +// Copyright (c) 2011 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. +// +// A handy class that takes care of setting up and destroying a +// sync_api::UserShare instance for unit tests that require one. +// +// The expected usage is to make this a component of your test fixture: +// +// class AwesomenessTest : public testing::Test { +// public: +// virtual void SetUp() { +// test_user_share_.SetUp(); +// } +// virtual void TearDown() { +// test_user_share_.TearDown(); +// } +// protected: +// TestUserShare test_user_share_; +// }; +// +// Then, in your tests: +// +// TEST_F(AwesomenessTest, IsMaximal) { +// sync_api::ReadTransaction trans(test_user_share_.user_share()); +// ... +// } +// + +#ifndef CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_USER_SHARE_H_ +#define CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_USER_SHARE_H_ +#pragma once + +#include "base/basictypes.h" +#include "chrome/browser/sync/internal_api/user_share.h" +#include "chrome/browser/sync/test/engine/test_directory_setter_upper.h" + +namespace browser_sync { + +class TestUserShare { + public: + TestUserShare(); + ~TestUserShare(); + + // Sets up the UserShare instance. Clears any existing database + // backing files that might exist on disk. + void SetUp(); + + // Undo everything done by SetUp(): closes the UserShare and deletes + // the backing files. Before closing the directory, this will run + // the directory invariant checks and perform the SaveChanges action + // on the user share's directory. + void TearDown(); + + // Non-NULL iff called between a call to SetUp() and TearDown(). + sync_api::UserShare* user_share(); + + private: + TestDirectorySetterUpper setter_upper_; + sync_api::UserShare user_share_; + + DISALLOW_COPY_AND_ASSIGN(TestUserShare); +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_ENGINE_TEST_USER_SHARE_H_ diff --git a/chrome/browser/sync/test/live_sync/PRESUBMIT.py b/chrome/browser/sync/test/live_sync/PRESUBMIT.py new file mode 100644 index 0000000..f49f215 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/PRESUBMIT.py @@ -0,0 +1,13 @@ +#!/usr/bin/python +# Copyright (c) 2011 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. + +"""Chromium presubmit script for src/chrome/browser/sync/test/live_sync. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts +for more details on the presubmit API built into gcl. +""" + +def GetPreferredTrySlaves(): + return ['win', 'linux', 'mac', 'win_sync', 'linux_sync', 'mac_sync'] diff --git a/chrome/browser/sync/test/live_sync/apps_helper.cc b/chrome/browser/sync/test/live_sync/apps_helper.cc new file mode 100644 index 0000000..eb68002 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/apps_helper.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2011 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/live_sync/apps_helper.h" + +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/browser/sync/test/live_sync/sync_extension_helper.h" +#include "chrome/common/extensions/extension.h" + +using sync_datatype_helper::test; + +namespace { + +std::string CreateFakeAppName(int index) { + return "fakeapp" + base::IntToString(index); +} + +} // namespace + +namespace apps_helper { + +bool HasSameAppsAsVerifier(int index) { + // TODO(akalin): We may want to filter out non-apps for some tests. + return SyncExtensionHelper::GetInstance()->ExtensionStatesMatch( + test()->GetProfile(index), test()->verifier()); +} + +bool AllProfilesHaveSameAppsAsVerifier() { + for (int i = 0; i < test()->num_clients(); ++i) { + if (!HasSameAppsAsVerifier(i)) { + LOG(ERROR) << "Profile " << i << " doesn't have the same apps as the" + " verifier profile."; + return false; + } + } + return true; +} + +void InstallApp(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->InstallExtension( + profile, CreateFakeAppName(index), Extension::TYPE_HOSTED_APP); +} + +void UninstallApp(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->UninstallExtension( + profile, CreateFakeAppName(index)); +} + +void EnableApp(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->EnableExtension( + profile, CreateFakeAppName(index)); +} + +void DisableApp(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->DisableExtension( + profile, CreateFakeAppName(index)); +} + +void IncognitoEnableApp(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->IncognitoEnableExtension( + profile, CreateFakeAppName(index)); +} + +void IncognitoDisableApp(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->IncognitoDisableExtension( + profile, CreateFakeAppName(index)); +} + +void InstallAppsPendingForSync(Profile* profile) { + SyncExtensionHelper::GetInstance()->InstallExtensionsPendingForSync( + profile, Extension::TYPE_HOSTED_APP); +} + +} // namespace apps_helper diff --git a/chrome/browser/sync/test/live_sync/apps_helper.h b/chrome/browser/sync/test/live_sync/apps_helper.h new file mode 100644 index 0000000..e1a1ca2 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/apps_helper.h @@ -0,0 +1,48 @@ +// Copyright (c) 2011 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_LIVE_SYNC_APPS_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_APPS_HELPER_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +class Profile; + +namespace apps_helper { + +// Returns true iff the profile with index |index| has the same apps as the +// verifier. +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); + +// Uninstalls the app for the given index from |profile|. Assumes that it was +// previously installed. +void UninstallApp(Profile* profile, int index); + +// Installs all pending synced apps for |profile|. +void InstallAppsPendingForSync(Profile* profile); + +// Enables the app for the given index on |profile|. +void EnableApp(Profile* profile, int index); + +// Disables the appfor the given index on |profile|. +void DisableApp(Profile* profile, int index); + +// Enables the app for the given index in incognito mode on |profile|. +void IncognitoEnableApp(Profile* profile, int index); + +// Disables the app for the given index in incognito mode on |profile|. +void IncognitoDisableApp(Profile* profile, int index); + +} // namespace apps_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_APPS_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/autofill_helper.cc b/chrome/browser/sync/test/live_sync/autofill_helper.cc new file mode 100644 index 0000000..a1a96ee --- /dev/null +++ b/chrome/browser/sync/test/live_sync/autofill_helper.cc @@ -0,0 +1,298 @@ +// Copyright (c) 2011 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/live_sync/autofill_helper.h" + +#include "chrome/browser/autofill/autofill_common_test.h" +#include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/browser/autofill/autofill_type.h" +#include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/autofill/personal_data_manager_observer.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/profile_sync_test_util.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/browser/webdata/autofill_entry.h" +#include "chrome/browser/webdata/autofill_table.h" +#include "chrome/browser/webdata/web_database.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/test/base/thread_observer_helper.h" +#include "webkit/glue/form_field.h" + +using base::WaitableEvent; +using sync_datatype_helper::test; +using testing::_; + +namespace { + +class GetAllAutofillEntries + : public base::RefCountedThreadSafe<GetAllAutofillEntries> { + public: + explicit GetAllAutofillEntries(WebDataService* web_data_service) + : web_data_service_(web_data_service), + done_event_(false, false) {} + + void Init() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask( + BrowserThread::DB, + FROM_HERE, + NewRunnableMethod(this, &GetAllAutofillEntries::Run)); + done_event_.Wait(); + } + + const std::vector<AutofillEntry>& entries() const { + return entries_; + } + + private: + friend class base::RefCountedThreadSafe<GetAllAutofillEntries>; + + void Run() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + web_data_service_->GetDatabase()->GetAutofillTable()->GetAllAutofillEntries( + &entries_); + done_event_.Signal(); + } + + WebDataService* web_data_service_; + base::WaitableEvent done_event_; + std::vector<AutofillEntry> entries_; +}; + +ACTION_P(SignalEvent, event) { + event->Signal(); +} + +class AutofillDBThreadObserverHelper : public DBThreadObserverHelper { + protected: + virtual void RegisterObservers() { + registrar_.Add(&observer_, + chrome::NOTIFICATION_AUTOFILL_ENTRIES_CHANGED, + NotificationService::AllSources()); + registrar_.Add(&observer_, + chrome::NOTIFICATION_AUTOFILL_PROFILE_CHANGED, + NotificationService::AllSources()); + } +}; + +class MockPersonalDataManagerObserver : public PersonalDataManagerObserver { + public: + MOCK_METHOD0(OnPersonalDataChanged, void()); +}; + +} // namespace + +namespace autofill_helper { + +AutofillProfile CreateAutofillProfile(ProfileType type) { + AutofillProfile profile; + switch (type) { + case PROFILE_MARION: + autofill_test::SetProfileInfoWithGuid(&profile, + "C837507A-6C3B-4872-AC14-5113F157D668", + "Marion", "Mitchell", "Morrison", + "johnwayne@me.xyz", "Fox", + "123 Zoo St.", "unit 5", "Hollywood", "CA", + "91601", "US", "12345678910", "01987654321"); + break; + case PROFILE_HOMER: + autofill_test::SetProfileInfoWithGuid(&profile, + "137DE1C3-6A30-4571-AC86-109B1ECFBE7F", + "Homer", "J.", "Simpson", + "homer@abc.com", "SNPP", + "1 Main St", "PO Box 1", "Springfield", "MA", + "94101", "US", "14155551212", "14155551313"); + break; + case PROFILE_FRASIER: + autofill_test::SetProfileInfoWithGuid(&profile, + "9A5E6872-6198-4688-BF75-0016E781BB0A", + "Frasier", "Winslow", "Crane", + "", "randomness", "", "Apt. 4", "Seattle", "WA", + "99121", "US", "0000000000", "ABCDEFGHIJK"); + break; + case PROFILE_NULL: + autofill_test::SetProfileInfoWithGuid(&profile, + "FE461507-7E13-4198-8E66-74C7DB6D8322", + "", "", "", "", "", "", "", "", "", "", "", "", ""); + break; + } + return profile; +} + +WebDataService* GetWebDataService(int index) { + return test()->GetProfile(index)->GetWebDataService(Profile::EXPLICIT_ACCESS); +} + +PersonalDataManager* GetPersonalDataManager(int index) { + return test()->GetProfile(index)->GetPersonalDataManager(); +} + +void AddKeys(int profile, const std::set<AutofillKey>& keys) { + std::vector<webkit_glue::FormField> form_fields; + for (std::set<AutofillKey>::const_iterator i = keys.begin(); + i != keys.end(); + ++i) { + webkit_glue::FormField field; + field.name = i->name(); + field.value = i->value(); + form_fields.push_back(field); + } + + WaitableEvent done_event(false, false); + scoped_refptr<AutofillDBThreadObserverHelper> observer_helper( + new AutofillDBThreadObserverHelper()); + observer_helper->Init(); + + EXPECT_CALL(*observer_helper->observer(), Observe(_, _, _)). + WillOnce(SignalEvent(&done_event)); + WebDataService* wds = GetWebDataService(profile); + wds->AddFormFields(form_fields); + done_event.Wait(); +} + +void RemoveKey(int profile, const AutofillKey& key) { + WaitableEvent done_event(false, false); + scoped_refptr<AutofillDBThreadObserverHelper> observer_helper( + new AutofillDBThreadObserverHelper()); + observer_helper->Init(); + + EXPECT_CALL(*observer_helper->observer(), Observe(_, _, _)). + WillOnce(SignalEvent(&done_event)); + WebDataService* wds = GetWebDataService(profile); + wds->RemoveFormValueForElementName(key.name(), key.value()); + done_event.Wait(); +} + +std::set<AutofillEntry> GetAllKeys(int profile) { + WebDataService* wds = GetWebDataService(profile); + scoped_refptr<GetAllAutofillEntries> get_all_entries = + new GetAllAutofillEntries(wds); + get_all_entries->Init(); + const std::vector<AutofillEntry>& all_entries = get_all_entries->entries(); + std::set<AutofillEntry> all_keys; + for (std::vector<AutofillEntry>::const_iterator it = all_entries.begin(); + it != all_entries.end(); ++it) { + all_keys.insert(*it); + } + return all_keys; +} + +bool KeysMatch(int profile_a, int profile_b) { + return GetAllKeys(profile_a) == GetAllKeys(profile_b); +} + +void SetProfiles(int profile, std::vector<AutofillProfile>* autofill_profiles) { + MockPersonalDataManagerObserver observer; + EXPECT_CALL(observer, OnPersonalDataChanged()). + WillOnce(QuitUIMessageLoop()); + PersonalDataManager* pdm = GetPersonalDataManager(profile); + pdm->SetObserver(&observer); + pdm->SetProfiles(autofill_profiles); + MessageLoop::current()->Run(); + pdm->RemoveObserver(&observer); +} + +void AddProfile(int profile, const AutofillProfile& autofill_profile) { + const std::vector<AutofillProfile*>& all_profiles = GetAllProfiles(profile); + std::vector<AutofillProfile> autofill_profiles; + for (size_t i = 0; i < all_profiles.size(); ++i) + autofill_profiles.push_back(*all_profiles[i]); + autofill_profiles.push_back(autofill_profile); + autofill_helper::SetProfiles(profile, &autofill_profiles); +} + +void RemoveProfile(int profile, const std::string& guid) { + const std::vector<AutofillProfile*>& all_profiles = GetAllProfiles(profile); + std::vector<AutofillProfile> autofill_profiles; + for (size_t i = 0; i < all_profiles.size(); ++i) { + if (all_profiles[i]->guid() != guid) + autofill_profiles.push_back(*all_profiles[i]); + } + autofill_helper::SetProfiles(profile, &autofill_profiles); +} + +void UpdateProfile(int profile, + const std::string& guid, + const AutofillType& type, + const string16& value) { + const std::vector<AutofillProfile*>& all_profiles = GetAllProfiles(profile); + std::vector<AutofillProfile> profiles; + for (size_t i = 0; i < all_profiles.size(); ++i) { + profiles.push_back(*all_profiles[i]); + if (all_profiles[i]->guid() == guid) + profiles.back().SetInfo(type.field_type(), value); + } + autofill_helper::SetProfiles(profile, &profiles); +} + +const std::vector<AutofillProfile*>& GetAllProfiles( + int profile) { + MockPersonalDataManagerObserver observer; + EXPECT_CALL(observer, OnPersonalDataChanged()). + WillOnce(QuitUIMessageLoop()); + PersonalDataManager* pdm = GetPersonalDataManager(profile); + pdm->SetObserver(&observer); + pdm->Refresh(); + MessageLoop::current()->Run(); + pdm->RemoveObserver(&observer); + return pdm->web_profiles(); +} + +int GetProfileCount(int profile) { + return GetAllProfiles(profile).size(); +} + +int GetKeyCount(int profile) { + return GetAllKeys(profile).size(); +} + +bool ProfilesMatch(int profile_a, int profile_b) { + const std::vector<AutofillProfile*>& autofill_profiles_a = + GetAllProfiles(profile_a); + std::map<std::string, AutofillProfile> autofill_profiles_a_map; + for (size_t i = 0; i < autofill_profiles_a.size(); ++i) { + const AutofillProfile* p = autofill_profiles_a[i]; + autofill_profiles_a_map[p->guid()] = *p; + } + + const std::vector<AutofillProfile*>& autofill_profiles_b = + GetAllProfiles(profile_b); + for (size_t i = 0; i < autofill_profiles_b.size(); ++i) { + const AutofillProfile* p = autofill_profiles_b[i]; + if (!autofill_profiles_a_map.count(p->guid())) { + LOG(ERROR) << "GUID " << p->guid() << " not found in profile " + << profile_b << "."; + return false; + } + AutofillProfile* expected_profile = &autofill_profiles_a_map[p->guid()]; + expected_profile->set_guid(p->guid()); + if (*expected_profile != *p) { + LOG(ERROR) << "Mismatch in profile with GUID " << p->guid() << "."; + return false; + } + autofill_profiles_a_map.erase(p->guid()); + } + + if (autofill_profiles_a_map.size()) { + LOG(ERROR) << "Entries present in Profile " << profile_a + << " but not in " << profile_b << "."; + return false; + } + return true; +} + +bool AllProfilesMatch() { + for (int i = 1; i < test()->num_clients(); ++i) { + if (!ProfilesMatch(0, i)) { + LOG(ERROR) << "Profile " << i << "does not contain the same autofill " + "profiles as profile 0."; + return false; + } + } + return true; +} + +} // namespace autofill_helper diff --git a/chrome/browser/sync/test/live_sync/autofill_helper.h b/chrome/browser/sync/test/live_sync/autofill_helper.h new file mode 100644 index 0000000..50732f5 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/autofill_helper.h @@ -0,0 +1,97 @@ +// Copyright (c) 2011 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_LIVE_SYNC_AUTOFILL_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_AUTOFILL_HELPER_H_ +#pragma once + +#include <set> +#include <string> +#include <vector> + +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" + +class AutofillEntry; +class AutofillKey; +class AutofillProfile; +class AutofillType; +class PersonalDataManager; +class WebDataService; + +namespace autofill_helper { + +enum ProfileType { + PROFILE_MARION, + PROFILE_HOMER, + PROFILE_FRASIER, + PROFILE_NULL +}; + +// Used to access the web data service within a particular sync profile. +WebDataService* GetWebDataService(int index) WARN_UNUSED_RESULT; + +// Used to access the personal data manager within a particular sync profile. +PersonalDataManager* GetPersonalDataManager(int index) WARN_UNUSED_RESULT; + +// Adds the form fields in |keys| to the WebDataService of sync profile +// |profile|. +void AddKeys(int profile, const std::set<AutofillKey>& keys); + +// Removes the form field in |key| from the WebDataService of sync profile +// |profile|. +void RemoveKey(int profile, const AutofillKey& key); + +// Gets all the form fields in the WebDataService of sync profile |profile|. +std::set<AutofillEntry> GetAllKeys(int profile) WARN_UNUSED_RESULT; + +// Compares the form fields in the WebDataServices of sync profiles +// |profile_a| and |profile_b|. Returns true if they match. +bool KeysMatch(int profile_a, int profile_b) WARN_UNUSED_RESULT; + +// Replaces the Autofill profiles in sync profile |profile| with +// |autofill_profiles|. +void SetProfiles(int profile, std::vector<AutofillProfile>* autofill_profiles); + +// Adds the autofill profile |autofill_profile| to sync profile |profile|. +void AddProfile(int profile, const AutofillProfile& autofill_profile); + +// Removes the autofill profile with guid |guid| from sync profile +// |profile|. +void RemoveProfile(int profile, const std::string& guid); + +// Updates the autofill profile with guid |guid| in sync profile |profile| +// to |type| and |value|. +void UpdateProfile(int profile, + const std::string& guid, + const AutofillType& type, + const string16& value); + +// Gets all the Autofill profiles in the PersonalDataManager of sync profile +// |profile|. +const std::vector<AutofillProfile*>& GetAllProfiles( + int profile) WARN_UNUSED_RESULT; + +// Returns the number of autofill profiles contained by sync profile +// |profile|. +int GetProfileCount(int profile); + +// Returns the number of autofill keys contained by sync profile |profile|. +int GetKeyCount(int profile); + +// Compares the Autofill profiles in the PersonalDataManagers of sync profiles +// |profile_a| and |profile_b|. Returns true if they match. +bool ProfilesMatch(int profile_a, int profile_b) WARN_UNUSED_RESULT; + +// Compares the autofill profiles for all sync profiles, and returns true if +// they all match. +bool AllProfilesMatch() WARN_UNUSED_RESULT; + +// Creates a test autofill profile based on the persona specified in |type|. +AutofillProfile CreateAutofillProfile(ProfileType type); + +} // namespace autofill_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_AUTOFILL_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/bookmarks_helper.cc b/chrome/browser/sync/test/live_sync/bookmarks_helper.cc new file mode 100644 index 0000000..18ed644 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/bookmarks_helper.cc @@ -0,0 +1,593 @@ +// Copyright (c) 2011 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/live_sync/bookmarks_helper.h" + +#include "base/rand_util.h" +#include "base/string_number_conversions.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/bookmarks/bookmark_model_observer.h" +#include "chrome/browser/bookmarks/bookmark_utils.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/glue/bookmark_change_processor.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/test/base/ui_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/models/tree_node_iterator.h" +#include "ui/gfx/codec/png_codec.h" + +using sync_datatype_helper::test; + +namespace { + +// Helper class used to wait for changes to take effect on the favicon of a +// particular bookmark node in a particular bookmark model. +class FaviconChangeObserver : public BookmarkModelObserver { + public: + FaviconChangeObserver(BookmarkModel* model, const BookmarkNode* node) + : model_(model), + node_(node), + wait_for_load_(false) { + model->AddObserver(this); + } + virtual ~FaviconChangeObserver() { + model_->RemoveObserver(this); + } + void WaitForGetFavicon() { + wait_for_load_ = true; + ui_test_utils::RunMessageLoop(); + ASSERT_TRUE(node_->is_favicon_loaded()); + } + void WaitForSetFavicon() { + wait_for_load_ = false; + ui_test_utils::RunMessageLoop(); + } + virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE {} + virtual void BookmarkNodeMoved(BookmarkModel* model, + const BookmarkNode* old_parent, + int old_index, + const BookmarkNode* new_parent, + int new_index) OVERRIDE {} + virtual void BookmarkNodeAdded(BookmarkModel* model, + const BookmarkNode* parent, + int index) OVERRIDE {} + virtual void BookmarkNodeRemoved(BookmarkModel* model, + const BookmarkNode* parent, + int old_index, + const BookmarkNode* node) OVERRIDE {} + virtual void BookmarkNodeChanged(BookmarkModel* model, + const BookmarkNode* node) OVERRIDE { + if (model == model_ && node == node_) + model->GetFavicon(node); + } + virtual void BookmarkNodeChildrenReordered( + BookmarkModel* model, + const BookmarkNode* node) OVERRIDE {} + virtual void BookmarkNodeFaviconChanged( + BookmarkModel* model, + const BookmarkNode* node) OVERRIDE { + if (model == model_ && node == node_) { + if (!wait_for_load_ || (wait_for_load_ && node->is_favicon_loaded())) + MessageLoopForUI::current()->Quit(); + } + } + + private: + BookmarkModel* model_; + const BookmarkNode* node_; + bool wait_for_load_; + DISALLOW_COPY_AND_ASSIGN(FaviconChangeObserver); +}; + +// A collection of URLs for which we have added favicons. Since loading a +// favicon is an asynchronous operation and doesn't necessarily invoke a +// callback, this collection is used to determine if we must wait for a URL's +// favicon to load or not. +std::set<GURL>* urls_with_favicons_ = NULL; + +// Returns the number of nodes of node type |node_type| in |model| whose +// titles match the string |title|. +int CountNodesWithTitlesMatching(BookmarkModel* model, + BookmarkNode::Type node_type, + const string16& title) { + ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node()); + // Walk through the model tree looking for bookmark nodes of node type + // |node_type| whose titles match |title|. + int count = 0; + while (iterator.has_next()) { + const BookmarkNode* node = iterator.Next(); + if ((node->type() == node_type) && (node->GetTitle() == title)) + ++count; + } + return count; +} + +// Checks if the favicon data in |bitmap_a| and |bitmap_b| are equivalent. +// Returns true if they match. +bool FaviconBitmapsMatch(const SkBitmap& bitmap_a, const SkBitmap& bitmap_b) { + if (bitmap_a.getSize() == 0U && bitmap_a.getSize() == 0U) + return true; + if ((bitmap_a.getSize() != bitmap_b.getSize()) || + (bitmap_a.width() != bitmap_b.width()) || + (bitmap_a.height() != bitmap_b.height())) { + LOG(ERROR) << "Favicon size mismatch: " << bitmap_a.getSize() << " (" + << bitmap_a.width() << "x" << bitmap_a.height() << ") vs. " + << bitmap_b.getSize() << " (" << bitmap_b.width() << "x" + << bitmap_b.height() << ")"; + return false; + } + SkAutoLockPixels bitmap_lock_a(bitmap_a); + SkAutoLockPixels bitmap_lock_b(bitmap_b); + void* node_pixel_addr_a = bitmap_a.getPixels(); + EXPECT_TRUE(node_pixel_addr_a); + void* node_pixel_addr_b = bitmap_b.getPixels(); + EXPECT_TRUE(node_pixel_addr_b); + if (memcmp(node_pixel_addr_a, node_pixel_addr_b, bitmap_a.getSize()) != 0) { + LOG(ERROR) << "Favicon bitmap mismatch"; + return false; + } else { + return true; + } +} + +// Gets the favicon associated with |node| in |model|. +const SkBitmap& GetFavicon(BookmarkModel* model, const BookmarkNode* node) { + // If a favicon wasn't explicitly set for a particular URL, simply return its + // blank favicon. + if (!urls_with_favicons_ || + urls_with_favicons_->find(node->url()) == urls_with_favicons_->end()) { + return node->favicon(); + } + // If a favicon was explicitly set, we may need to wait for it to be loaded + // via BookmarkModel::GetFavIcon(), which is an asynchronous operation. + if (!node->is_favicon_loaded()) { + FaviconChangeObserver observer(model, node); + model->GetFavicon(node); + observer.WaitForGetFavicon(); + } + EXPECT_TRUE(node->is_favicon_loaded()); + return node->favicon(); +} + +// Checks if the favicon in |node_a| from |model_a| matches that of |node_b| +// from |model_b|. Returns true if they match. +bool FaviconsMatch(BookmarkModel* model_a, + BookmarkModel* model_b, + const BookmarkNode* node_a, + const BookmarkNode* node_b) { + const SkBitmap& bitmap_a = GetFavicon(model_a, node_a); + const SkBitmap& bitmap_b = GetFavicon(model_b, node_b); + return FaviconBitmapsMatch(bitmap_a, bitmap_b); +} + +// Does a deep comparison of BookmarkNode fields in |model_a| and |model_b|. +// Returns true if they are all equal. +bool NodesMatch(const BookmarkNode* node_a, const BookmarkNode* node_b) { + if (node_a == NULL || node_b == NULL) + return node_a == node_b; + if (node_a->is_folder() != node_b->is_folder()) { + LOG(ERROR) << "Cannot compare folder with bookmark"; + return false; + } + if (node_a->GetTitle() != node_b->GetTitle()) { + LOG(ERROR) << "Title mismatch: " << node_a->GetTitle() << " vs. " + << node_b->GetTitle(); + return false; + } + if (node_a->url() != node_b->url()) { + LOG(ERROR) << "URL mismatch: " << node_a->url() << " vs. " + << node_b->url(); + return false; + } + if (node_a->parent()->GetIndexOf(node_a) != + node_b->parent()->GetIndexOf(node_b)) { + LOG(ERROR) << "Index mismatch: " + << node_a->parent()->GetIndexOf(node_a) << " vs. " + << node_b->parent()->GetIndexOf(node_b); + return false; + } + return true; +} + +// Checks if the hierarchies in |model_a| and |model_b| are equivalent in +// terms of the data model and favicon. Returns true if they both match. +// Note: Some peripheral fields like creation times are allowed to mismatch. +bool BookmarkModelsMatch(BookmarkModel* model_a, BookmarkModel* model_b) { + bool ret_val = true; + ui::TreeNodeIterator<const BookmarkNode> iterator_a(model_a->root_node()); + ui::TreeNodeIterator<const BookmarkNode> iterator_b(model_b->root_node()); + while (iterator_a.has_next()) { + const BookmarkNode* node_a = iterator_a.Next(); + if (!iterator_b.has_next()) { + LOG(ERROR) << "Models do not match."; + return false; + } + const BookmarkNode* node_b = iterator_b.Next(); + ret_val = ret_val && NodesMatch(node_a, node_b); + if (node_a->is_folder() || node_b->is_folder()) + continue; + ret_val = ret_val && FaviconsMatch(model_a, model_b, node_a, node_b); + } + ret_val = ret_val && (!iterator_b.has_next()); + return ret_val; +} + +// Finds the node in the verifier bookmark model that corresponds to +// |foreign_node| in |foreign_model| and stores its address in |result|. +void FindNodeInVerifier(BookmarkModel* foreign_model, + const BookmarkNode* foreign_node, + const BookmarkNode** result) { + // Climb the tree. + std::stack<int> path; + const BookmarkNode* walker = foreign_node; + while (walker != foreign_model->root_node()) { + path.push(walker->parent()->GetIndexOf(walker)); + walker = walker->parent(); + } + + // Swing over to the other tree. + walker = bookmarks_helper::GetVerifierBookmarkModel()->root_node(); + + // Climb down. + while (!path.empty()) { + ASSERT_TRUE(walker->is_folder()); + ASSERT_LT(path.top(), walker->child_count()); + walker = walker->GetChild(path.top()); + path.pop(); + } + + ASSERT_TRUE(NodesMatch(foreign_node, walker)); + *result = walker; +} + +} // namespace + + +namespace bookmarks_helper { + +BookmarkModel* GetBookmarkModel(int index) { + return test()->GetProfile(index)->GetBookmarkModel(); +} + +const BookmarkNode* GetBookmarkBarNode(int index) { + return GetBookmarkModel(index)->bookmark_bar_node(); +} + +const BookmarkNode* GetOtherNode(int index) { + return GetBookmarkModel(index)->other_node(); +} + +BookmarkModel* GetVerifierBookmarkModel() { + return test()->verifier()->GetBookmarkModel(); +} + +const BookmarkNode* AddURL(int profile, + const std::wstring& title, + const GURL& url) { + return AddURL(profile, GetBookmarkBarNode(profile), 0, title, url); +} + +const BookmarkNode* AddURL(int profile, + int index, + const std::wstring& title, + const GURL& url) { + return AddURL(profile, GetBookmarkBarNode(profile), index, title, url); +} + +const BookmarkNode* AddURL(int profile, + const BookmarkNode* parent, + int index, + const std::wstring& title, + const GURL& url) { + if (GetBookmarkModel(profile)->GetNodeByID(parent->id()) != parent) { + LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to " + << "Profile " << profile; + return NULL; + } + const BookmarkNode* result = GetBookmarkModel(profile)-> + AddURL(parent, index, WideToUTF16(title), url); + if (!result) { + LOG(ERROR) << "Could not add bookmark " << title << " to Profile " + << profile; + return NULL; + } + if (test()->use_verifier()) { + const BookmarkNode* v_parent = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); + const BookmarkNode* v_node = GetVerifierBookmarkModel()-> + AddURL(v_parent, index, WideToUTF16(title), url); + if (!v_node) { + LOG(ERROR) << "Could not add bookmark " << title << " to the verifier"; + return NULL; + } + EXPECT_TRUE(NodesMatch(v_node, result)); + } + return result; +} + +const BookmarkNode* AddFolder(int profile, + const std::wstring& title) { + return AddFolder(profile, GetBookmarkBarNode(profile), 0, title); +} + +const BookmarkNode* AddFolder(int profile, + int index, + const std::wstring& title) { + return AddFolder(profile, GetBookmarkBarNode(profile), index, title); +} + +const BookmarkNode* AddFolder(int profile, + const BookmarkNode* parent, + int index, + const std::wstring& title) { + if (GetBookmarkModel(profile)->GetNodeByID(parent->id()) != parent) { + LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to " + << "Profile " << profile; + return NULL; + } + const BookmarkNode* result = + GetBookmarkModel(profile)->AddFolder(parent, index, WideToUTF16(title)); + EXPECT_TRUE(result); + if (!result) { + LOG(ERROR) << "Could not add folder " << title << " to Profile " + << profile; + return NULL; + } + if (test()->use_verifier()) { + const BookmarkNode* v_parent = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); + const BookmarkNode* v_node = GetVerifierBookmarkModel()->AddFolder( + v_parent, index, WideToUTF16(title)); + if (!v_node) { + LOG(ERROR) << "Could not add folder " << title << " to the verifier"; + return NULL; + } + EXPECT_TRUE(NodesMatch(v_node, result)); + } + return result; +} + +void SetTitle(int profile, + const BookmarkNode* node, + const std::wstring& new_title) { + ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) + << "Node " << node->GetTitle() << " does not belong to " + << "Profile " << profile; + if (test()->use_verifier()) { + const BookmarkNode* v_node = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); + GetVerifierBookmarkModel()->SetTitle(v_node, WideToUTF16(new_title)); + } + GetBookmarkModel(profile)->SetTitle(node, WideToUTF16(new_title)); +} + +void SetFavicon(int profile, + const BookmarkNode* node, + const std::vector<unsigned char>& icon_bytes_vector) { + ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) + << "Node " << node->GetTitle() << " does not belong to " + << "Profile " << profile; + ASSERT_EQ(BookmarkNode::URL, node->type()) + << "Node " << node->GetTitle() << " must be a url."; + if (urls_with_favicons_ == NULL) + urls_with_favicons_ = new std::set<GURL>(); + urls_with_favicons_->insert(node->url()); + if (test()->use_verifier()) { + const BookmarkNode* v_node = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); + FaviconChangeObserver v_observer(GetVerifierBookmarkModel(), v_node); + browser_sync::BookmarkChangeProcessor::ApplyBookmarkFavicon( + v_node, test()->verifier(), icon_bytes_vector); + v_observer.WaitForSetFavicon(); + } + FaviconChangeObserver observer(GetBookmarkModel(profile), node); + browser_sync::BookmarkChangeProcessor::ApplyBookmarkFavicon( + node, test()->GetProfile(profile), icon_bytes_vector); + observer.WaitForSetFavicon(); +} + +const BookmarkNode* SetURL(int profile, + const BookmarkNode* node, + const GURL& new_url) { + if (GetBookmarkModel(profile)->GetNodeByID(node->id()) != node) { + LOG(ERROR) << "Node " << node->GetTitle() << " does not belong to " + << "Profile " << profile; + return NULL; + } + if (test()->use_verifier()) { + const BookmarkNode* v_node = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); + bookmark_utils::ApplyEditsWithNoFolderChange( + GetVerifierBookmarkModel(), + v_node->parent(), + BookmarkEditor::EditDetails(v_node), + v_node->GetTitle(), + new_url); + } + return bookmark_utils::ApplyEditsWithNoFolderChange( + GetBookmarkModel(profile), + node->parent(), + BookmarkEditor::EditDetails(node), + node->GetTitle(), + new_url); +} + +void Move(int profile, + const BookmarkNode* node, + const BookmarkNode* new_parent, + int index) { + ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) + << "Node " << node->GetTitle() << " does not belong to " + << "Profile " << profile; + if (test()->use_verifier()) { + const BookmarkNode* v_new_parent = NULL; + const BookmarkNode* v_node = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), new_parent, &v_new_parent); + FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); + GetVerifierBookmarkModel()->Move(v_node, v_new_parent, index); + } + GetBookmarkModel(profile)->Move(node, new_parent, index); +} + +void Remove(int profile, + const BookmarkNode* parent, + int index) { + ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent) + << "Node " << parent->GetTitle() << " does not belong to " + << "Profile " << profile; + if (test()->use_verifier()) { + const BookmarkNode* v_parent = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); + ASSERT_TRUE(NodesMatch(parent->GetChild(index), v_parent->GetChild(index))); + GetVerifierBookmarkModel()->Remove(v_parent, index); + } + GetBookmarkModel(profile)->Remove(parent, index); +} + +void SortChildren(int profile, const BookmarkNode* parent) { + ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent) + << "Node " << parent->GetTitle() << " does not belong to " + << "Profile " << profile; + if (test()->use_verifier()) { + const BookmarkNode* v_parent = NULL; + FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); + GetVerifierBookmarkModel()->SortChildren(v_parent); + } + GetBookmarkModel(profile)->SortChildren(parent); +} + +void ReverseChildOrder(int profile, const BookmarkNode* parent) { + ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent) + << "Node " << parent->GetTitle() << " does not belong to " + << "Profile " << profile; + int child_count = parent->child_count(); + if (child_count <= 0) + return; + for (int index = 0; index < child_count; ++index) { + Move(profile, parent->GetChild(index), parent, child_count - index); + } +} + +bool ModelMatchesVerifier(int profile) { + if (!test()->use_verifier()) { + LOG(ERROR) << "Illegal to call ModelMatchesVerifier() after " + << "DisableVerifier(). Use ModelsMatch() instead."; + return false; + } + return BookmarkModelsMatch(GetVerifierBookmarkModel(), + GetBookmarkModel(profile)); +} + +bool AllModelsMatchVerifier() { + for (int i = 0; i < test()->num_clients(); ++i) { + if (!ModelMatchesVerifier(i)) { + LOG(ERROR) << "Model " << i << " does not match the verifier."; + return false; + } + } + return true; +} + +bool ModelsMatch(int profile_a, int profile_b) { + return BookmarkModelsMatch(GetBookmarkModel(profile_a), + GetBookmarkModel(profile_b)); +} + +bool AllModelsMatch() { + for (int i = 1; i < test()->num_clients(); ++i) { + if (!ModelsMatch(0, i)) { + LOG(ERROR) << "Model " << i << " does not match Model 0."; + return false; + } + } + return true; +} + +bool ContainsDuplicateBookmarks(int profile) { + ui::TreeNodeIterator<const BookmarkNode> iterator( + GetBookmarkModel(profile)->root_node()); + while (iterator.has_next()) { + const BookmarkNode* node = iterator.Next(); + if (node->is_folder()) + continue; + std::vector<const BookmarkNode*> nodes; + GetBookmarkModel(profile)->GetNodesByURL(node->url(), &nodes); + EXPECT_TRUE(nodes.size() >= 1); + for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) { + if (node->id() != (*it)->id() && + node->parent() == (*it)->parent() && + node->GetTitle() == (*it)->GetTitle()){ + return true; + } + } + } + return false; +} + +const BookmarkNode* GetUniqueNodeByURL(int profile, const GURL& url) { + std::vector<const BookmarkNode*> nodes; + GetBookmarkModel(profile)->GetNodesByURL(url, &nodes); + EXPECT_EQ(1U, nodes.size()); + if (nodes.empty()) + return NULL; + return nodes[0]; +} + +int CountBookmarksWithTitlesMatching(int profile, const std::wstring& title) { + return CountNodesWithTitlesMatching(GetBookmarkModel(profile), + BookmarkNode::URL, + WideToUTF16(title)); +} + +int CountFoldersWithTitlesMatching(int profile, const std::wstring& title) { + return CountNodesWithTitlesMatching(GetBookmarkModel(profile), + BookmarkNode::FOLDER, + WideToUTF16(title)); +} + +std::vector<unsigned char> CreateFavicon(int seed) { + const int w = 16; + const int h = 16; + SkBitmap bmp; + bmp.setConfig(SkBitmap::kARGB_8888_Config, w, h); + bmp.allocPixels(); + uint32_t* src_data = bmp.getAddr32(0, 0); + for (int i = 0; i < w * h; ++i) { + src_data[i] = SkPreMultiplyARGB((seed + i) % 255, + (seed + i) % 250, + (seed + i) % 245, + (seed + i) % 240); + } + std::vector<unsigned char> favicon; + gfx::PNGCodec::EncodeBGRASkBitmap(bmp, false, &favicon); + return favicon; +} + +std::string IndexedURL(int i) { + return StringPrintf("http://www.host.ext:1234/path/filename/%d", i); +} + +std::wstring IndexedURLTitle(int i) { + return StringPrintf(L"URL Title %d", i); +} + +std::wstring IndexedFolderName(int i) { + return StringPrintf(L"Folder Name %d", i); +} + +std::wstring IndexedSubfolderName(int i) { + return StringPrintf(L"Subfolder Name %d", i); +} + +std::wstring IndexedSubsubfolderName(int i) { + return StringPrintf(L"Subsubfolder Name %d", i); +} + +} // namespace bookmarks_helper diff --git a/chrome/browser/sync/test/live_sync/bookmarks_helper.h b/chrome/browser/sync/test/live_sync/bookmarks_helper.h new file mode 100644 index 0000000..8de894d --- /dev/null +++ b/chrome/browser/sync/test/live_sync/bookmarks_helper.h @@ -0,0 +1,184 @@ +// Copyright (c) 2011 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_LIVE_SYNC_BOOKMARKS_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_BOOKMARKS_HELPER_H_ +#pragma once + +#include <set> +#include <string> +#include <vector> + +#include "base/compiler_specific.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" + +class GURL; +class Profile; + +namespace bookmarks_helper { + +// Used to access the bookmark model within a particular sync profile. +BookmarkModel* GetBookmarkModel(int index) WARN_UNUSED_RESULT; + +// Used to access the bookmark bar within a particular sync profile. +const BookmarkNode* GetBookmarkBarNode(int index) WARN_UNUSED_RESULT; + +// Used to access the "other bookmarks" node within a particular sync profile. +const BookmarkNode* GetOtherNode(int index) WARN_UNUSED_RESULT; + +// Used to access the bookmarks within the verifier sync profile. +BookmarkModel* GetVerifierBookmarkModel() WARN_UNUSED_RESULT; + +// Adds a URL with address |url| and title |title| to the bookmark bar of +// profile |profile|. Returns a pointer to the node that was added. +const BookmarkNode* AddURL( + int profile, + const std::wstring& title, + const GURL& url) WARN_UNUSED_RESULT; + +// Adds a URL with address |url| and title |title| to the bookmark bar of +// profile |profile| at position |index|. Returns a pointer to the node that +// was added. +const BookmarkNode* AddURL( + int profile, + int index, + const std::wstring& title, + const GURL& url) WARN_UNUSED_RESULT; + +// Adds a URL with address |url| and title |title| under the node |parent| of +// profile |profile| at position |index|. Returns a pointer to the node that +// was added. +const BookmarkNode* AddURL( + int profile, + const BookmarkNode* parent, + int index, + const std::wstring& title, + const GURL& url) WARN_UNUSED_RESULT; + +// Adds a folder named |title| to the bookmark bar of profile |profile|. +// Returns a pointer to the folder that was added. +const BookmarkNode* AddFolder( + int profile, + const std::wstring& title) WARN_UNUSED_RESULT; + +// Adds a folder named |title| to the bookmark bar of profile |profile| at +// position |index|. Returns a pointer to the folder that was added. +const BookmarkNode* AddFolder( + int profile, + int index, + const std::wstring& title) WARN_UNUSED_RESULT; + +// Adds a folder named |title| to the node |parent| in the bookmark model of +// profile |profile| at position |index|. Returns a pointer to the node that +// was added. +const BookmarkNode* AddFolder( + int profile, + const BookmarkNode* parent, + int index, + const std::wstring& title) WARN_UNUSED_RESULT; + +// Changes the title of the node |node| in the bookmark model of profile +// |profile| to |new_title|. +void SetTitle(int profile, + const BookmarkNode* node, + const std::wstring& new_title); + +// Sets the favicon of the node |node| (of type BookmarkNode::URL) in the +// bookmark model of profile |profile| using the data in |icon_bytes_vector|. +void SetFavicon( + int profile, + const BookmarkNode* node, + const std::vector<unsigned char>& icon_bytes_vector); + +// Changes the url of the node |node| in the bookmark model of profile +// |profile| to |new_url|. Returns a pointer to the node with the changed url. +const BookmarkNode* SetURL( + int profile, + const BookmarkNode* node, + const GURL& new_url) WARN_UNUSED_RESULT; + +// Moves the node |node| in the bookmark model of profile |profile| so it ends +// up under the node |new_parent| at position |index|. +void Move( + int profile, + const BookmarkNode* node, + const BookmarkNode* new_parent, + int index); + +// Removes the node in the bookmark model of profile |profile| under the node +// |parent| at position |index|. +void Remove(int profile, const BookmarkNode* parent, int index); + +// Sorts the children of the node |parent| in the bookmark model of profile +// |profile|. +void SortChildren(int profile, const BookmarkNode* parent); + +// Reverses the order of the children of the node |parent| in the bookmark +// model of profile |profile|. +void ReverseChildOrder(int profile, const BookmarkNode* parent); + +// Checks if the bookmark model of profile |profile| matches the verifier +// bookmark model. Returns true if they match. +bool ModelMatchesVerifier(int profile) WARN_UNUSED_RESULT; + +// Checks if the bookmark models of all sync profiles match the verifier +// bookmark model. Returns true if they match. +bool AllModelsMatchVerifier() WARN_UNUSED_RESULT; + +// Checks if the bookmark models of |profile_a| and |profile_b| match each +// other. Returns true if they match. +bool ModelsMatch(int profile_a, int profile_b) WARN_UNUSED_RESULT; + +// Checks if the bookmark models of all sync profiles match each other. Does +// not compare them with the verifier bookmark model. Returns true if they +// match. +bool AllModelsMatch() WARN_UNUSED_RESULT; + +// Checks if the bookmark model of profile |profile| contains any instances of +// two bookmarks with the same URL under the same parent folder. Returns true +// if even one instance is found. +bool ContainsDuplicateBookmarks(int profile); + +// Gets the node in the bookmark model of profile |profile| that has the url +// |url|. Note: Only one instance of |url| is assumed to be present. +const BookmarkNode* GetUniqueNodeByURL( + int profile, + const GURL& url) WARN_UNUSED_RESULT; + +// Returns the number of bookmarks in bookmark model of profile |profile| +// whose titles match the string |title|. +int CountBookmarksWithTitlesMatching( + int profile, + const std::wstring& title) WARN_UNUSED_RESULT; + +// Returns the number of bookmark folders in the bookmark model of profile +// |profile| whose titles contain the query string |title|. +int CountFoldersWithTitlesMatching( + int profile, + const std::wstring& title) WARN_UNUSED_RESULT; + +// Creates a unique favicon using |seed|. +std::vector<unsigned char> CreateFavicon(int seed); + +// Returns a URL identifiable by |i|. +std::string IndexedURL(int i); + +// Returns a URL title identifiable by |i|. +std::wstring IndexedURLTitle(int i); + +// Returns a folder name identifiable by |i|. +std::wstring IndexedFolderName(int i); + +// Returns a subfolder name identifiable by |i|. +std::wstring IndexedSubfolderName(int i); + +// Returns a subsubfolder name identifiable by |i|. +std::wstring IndexedSubsubfolderName(int i); + +} // namespace bookmarks_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_BOOKMARKS_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/extensions_helper.cc b/chrome/browser/sync/test/live_sync/extensions_helper.cc new file mode 100644 index 0000000..6bd9a20 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/extensions_helper.cc @@ -0,0 +1,125 @@ +// Copyright (c) 2011 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/live_sync/extensions_helper.h" + +#include <cstring> + +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/browser/sync/test/live_sync/sync_extension_helper.h" +#include "chrome/common/extensions/extension.h" + +using sync_datatype_helper::test; + +namespace extensions_helper { + +const char extension_name_prefix[] = "fakeextension"; + +bool HasSameExtensionsAsVerifier(int index) { + return SyncExtensionHelper::GetInstance()->ExtensionStatesMatch( + test()->GetProfile(index), test()->verifier()); +} + +bool AllProfilesHaveSameExtensionsAsVerifier() { + for (int i = 0; i < test()->num_clients(); ++i) { + if (!HasSameExtensionsAsVerifier(i)) { + LOG(ERROR) << "Profile " << i << " doesn't have the same extensions as" + " the verifier profile."; + return false; + } + } + return true; +} + +bool AllProfilesHaveSameExtensions() { + for (int i = 1; i < test()->num_clients(); ++i) { + if (!SyncExtensionHelper::GetInstance()->ExtensionStatesMatch( + test()->GetProfile(0), test()->GetProfile(i))) { + LOG(ERROR) << "Profile " << i << " doesnt have the same extensions as" + " profile 0."; + return false; + } + } + return true; +} + + +void InstallExtension(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->InstallExtension( + profile, CreateFakeExtensionName(index), Extension::TYPE_EXTENSION); +} + +void UninstallExtension(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->UninstallExtension( + profile, CreateFakeExtensionName(index)); +} + +std::vector<int> GetInstalledExtensions(Profile* profile) { + std::vector<int> indices; + std::vector<std::string> names = + SyncExtensionHelper::GetInstance()->GetInstalledExtensionNames(profile); + for (std::vector<std::string>::const_iterator it = names.begin(); + it != names.end(); ++it) { + int index; + if (ExtensionNameToIndex(*it, &index)) { + indices.push_back(index); + } + } + return indices; +} + +void EnableExtension(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->EnableExtension( + profile, CreateFakeExtensionName(index)); +} + +void DisableExtension(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->DisableExtension( + profile, CreateFakeExtensionName(index)); +} + +bool IsExtensionEnabled(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->IsExtensionEnabled( + profile, CreateFakeExtensionName(index)); +} + +void IncognitoEnableExtension(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->IncognitoEnableExtension( + profile, CreateFakeExtensionName(index)); +} + +void IncognitoDisableExtension(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->IncognitoDisableExtension( + profile, CreateFakeExtensionName(index)); +} + +bool IsIncognitoEnabled(Profile* profile, int index) { + return SyncExtensionHelper::GetInstance()->IsIncognitoEnabled( + profile, CreateFakeExtensionName(index)); +} + +void InstallExtensionsPendingForSync(Profile* profile) { + SyncExtensionHelper::GetInstance()->InstallExtensionsPendingForSync( + profile, Extension::TYPE_EXTENSION); +} + +std::string CreateFakeExtensionName(int index) { + return extension_name_prefix + base::IntToString(index); +} + +bool ExtensionNameToIndex(const std::string& name, int* index) { + if (!StartsWithASCII(name, extension_name_prefix, true) || + !base::StringToInt(name.substr(strlen(extension_name_prefix)), index)) { + LOG(WARNING) << "Unable to convert extension name \"" << name + << "\" to index"; + return false; + } + return true; +} + +} // namespace extensions_helper diff --git a/chrome/browser/sync/test/live_sync/extensions_helper.h b/chrome/browser/sync/test/live_sync/extensions_helper.h new file mode 100644 index 0000000..7103bca --- /dev/null +++ b/chrome/browser/sync/test/live_sync/extensions_helper.h @@ -0,0 +1,73 @@ +// Copyright (c) 2011 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_LIVE_SYNC_EXTENSIONS_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_EXTENSIONS_HELPER_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +class Profile; + +namespace extensions_helper { + +// Returns true iff the profile with index |index| has the same extensions +// as the verifier. +bool HasSameExtensionsAsVerifier(int index) WARN_UNUSED_RESULT; + +// Returns true iff all existing profiles have the same extensions +// as the verifier. +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); + +// Uninstalls the extension for the given index from |profile|. Assumes that +// it was previously installed. +void UninstallExtension(Profile* profile, int index); + +// Returns a vector containing the indices of all currently installed +// test extensions on |profile|. +std::vector<int> GetInstalledExtensions(Profile* profile); + +// Installs all pending synced extensions for |profile|. +void InstallExtensionsPendingForSync(Profile* profile); + +// Enables the extension for the given index on |profile|. +void EnableExtension(Profile* profile, int index); + +// Disables the extension for the given index on |profile|. +void DisableExtension(Profile* profile, int index); + +// Returns true if the extension with index |index| is enabled on |profile|. +bool IsExtensionEnabled(Profile* profile, int index); + +// Enables the extension for the given index in incognito mode on |profile|. +void IncognitoEnableExtension(Profile* profile, int index); + +// Disables the extension for the given index in incognito mode on |profile|. +void IncognitoDisableExtension(Profile* profile, int index); + +// Returns true if the extension with index |index| is enabled in incognito +// mode on |profile|. +bool IsIncognitoEnabled(Profile* profile, int index); + +// Returns a unique extension name based in the integer |index|. +std::string CreateFakeExtensionName(int index); + +// Converts a fake extension name back into the index used to generate it. +// Returns true if successful, false on failure. +bool ExtensionNameToIndex(const std::string& name, int* index); + +} // namespace extensions_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_EXTENSIONS_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/live_sync_test.cc b/chrome/browser/sync/test/live_sync/live_sync_test.cc new file mode 100644 index 0000000..d47f34e --- /dev/null +++ b/chrome/browser/sync/test/live_sync/live_sync_test.cc @@ -0,0 +1,632 @@ +// Copyright (c) 2011 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/live_sync/live_sync_test.h" + +#include <vector> + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/path_service.h" +#include "base/stringprintf.h" +#include "base/string_util.h" +#include "base/synchronization/waitable_event.h" +#include "base/task.h" +#include "base/test/test_timeouts.h" +#include "base/threading/platform_thread.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/password_manager/encryptor.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/sync/notifier/p2p_notifier.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/browser/browser_thread.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "content/common/url_fetcher.h" +#include "content/test/test_url_fetcher_factory.h" +#include "googleurl/src/gurl.h" +#include "net/base/escape.h" +#include "net/base/network_change_notifier.h" +#include "net/proxy/proxy_config.h" +#include "net/proxy/proxy_config_service_fixed.h" +#include "net/proxy/proxy_service.h" +#include "net/test/test_server.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" +#include "net/url_request/url_request_status.h" + +namespace switches { +const char kPasswordFileForTest[] = "password-file-for-test"; +const char kSyncUserForTest[] = "sync-user-for-test"; +const char kSyncPasswordForTest[] = "sync-password-for-test"; +const char kSyncServerCommandLine[] = "sync-server-command-line"; +} + +namespace { +// The URLs for different calls in the Google Accounts programmatic login API. +const char kClientLoginUrl[] = "https://www.google.com/accounts/ClientLogin"; +const char kGetUserInfoUrl[] = "https://www.google.com/accounts/GetUserInfo"; +const char kIssueAuthTokenUrl[] = + "https://www.google.com/accounts/IssueAuthToken"; +const char kSearchDomainCheckUrl[] = + "https://www.google.com/searchdomaincheck?format=domain&type=chrome"; +} + +// Helper class that checks whether a sync test server is running or not. +class SyncServerStatusChecker : public URLFetcher::Delegate { + public: + SyncServerStatusChecker() : running_(false) {} + + virtual void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const net::URLRequestStatus& status, + int response_code, + const net::ResponseCookies& cookies, + const std::string& data) { + running_ = (status.status() == net::URLRequestStatus::SUCCESS && + response_code == 200 && data.find("ok") == 0); + MessageLoop::current()->Quit(); + } + + bool running() const { return running_; } + + private: + bool running_; +}; + +class SetProxyConfigTask : public Task { + public: + SetProxyConfigTask(base::WaitableEvent* done, + net::URLRequestContextGetter* url_request_context_getter, + const net::ProxyConfig& proxy_config) + : done_(done), + url_request_context_getter_(url_request_context_getter), + proxy_config_(proxy_config) { + } + + void Run() { + net::ProxyService* proxy_service = + url_request_context_getter_->GetURLRequestContext()->proxy_service(); + proxy_service->ResetConfigService( + new net::ProxyConfigServiceFixed(proxy_config_)); + done_->Signal(); + } + + private: + base::WaitableEvent* done_; + net::URLRequestContextGetter* url_request_context_getter_; + net::ProxyConfig proxy_config_; +}; + +LiveSyncTest::LiveSyncTest(TestType test_type) + : sync_server_(net::TestServer::TYPE_SYNC, FilePath()), + test_type_(test_type), + server_type_(SERVER_TYPE_UNDECIDED), + num_clients_(-1), + use_verifier_(true), + test_server_handle_(base::kNullProcessHandle) { + InProcessBrowserTest::set_show_window(true); + sync_datatype_helper::AssociateWithTest(this); + switch (test_type_) { + case SINGLE_CLIENT: { + num_clients_ = 1; + break; + } + case TWO_CLIENT: { + num_clients_ = 2; + break; + } + case MULTIPLE_CLIENT: { + num_clients_ = 3; + break; + } + case MANY_CLIENT: { + num_clients_ = 10; + break; + } + } +} + +LiveSyncTest::~LiveSyncTest() {} + +void LiveSyncTest::SetUp() { + CommandLine* cl = CommandLine::ForCurrentProcess(); + if (cl->HasSwitch(switches::kPasswordFileForTest)) { + ReadPasswordFile(); + } else if (cl->HasSwitch(switches::kSyncUserForTest) && + cl->HasSwitch(switches::kSyncPasswordForTest)) { + username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest); + password_ = cl->GetSwitchValueASCII(switches::kSyncPasswordForTest); + } else { + SetupMockGaiaResponses(); + } + + if (!cl->HasSwitch(switches::kSyncServiceURL) && + !cl->HasSwitch(switches::kSyncServerCommandLine)) { + // If neither a sync server URL nor a sync server command line is + // provided, start up a local python sync test server and point Chrome + // to its URL. This is the most common configuration, and the only + // one that makes sense for most developers. + server_type_ = LOCAL_PYTHON_SERVER; + } else if (cl->HasSwitch(switches::kSyncServiceURL) && + cl->HasSwitch(switches::kSyncServerCommandLine)) { + // If a sync server URL and a sync server command line are provided, + // start up a local sync server by running the command line. Chrome + // will connect to the server at the URL that was provided. + server_type_ = LOCAL_LIVE_SERVER; + } else if (cl->HasSwitch(switches::kSyncServiceURL) && + !cl->HasSwitch(switches::kSyncServerCommandLine)) { + // If a sync server URL is provided, but not a server command line, + // it is assumed that the server is already running. Chrome will + // automatically connect to it at the URL provided. There is nothing + // to do here. + server_type_ = EXTERNAL_LIVE_SERVER; + } else { + // If a sync server command line is provided, but not a server URL, + // we flag an error. + LOG(FATAL) << "Can't figure out how to run a server."; + } + + if (username_.empty() || password_.empty()) + LOG(FATAL) << "Cannot run sync tests without GAIA credentials."; + + // Mock the Mac Keychain service. The real Keychain can block on user input. +#if defined(OS_MACOSX) + Encryptor::UseMockKeychain(true); +#endif + + // Yield control back to the InProcessBrowserTest framework. + InProcessBrowserTest::SetUp(); +} + +void LiveSyncTest::TearDown() { + // Allow the InProcessBrowserTest framework to perform its tear down. + InProcessBrowserTest::TearDown(); + + // Stop the local python test server. This is a no-op if one wasn't started. + TearDownLocalPythonTestServer(); + + // Stop the local sync test server. This is a no-op if one wasn't started. + TearDownLocalTestServer(); +} + +void LiveSyncTest::SetUpCommandLine(CommandLine* cl) { + AddTestSwitches(cl); + AddOptionalTypesToCommandLine(cl); +} + +void LiveSyncTest::AddTestSwitches(CommandLine* cl) { + // TODO(rsimha): Until we implement a fake Tango server against which tests + // can run, we need to set the --sync-notification-method to "p2p". + if (!cl->HasSwitch(switches::kSyncNotificationMethod)) + cl->AppendSwitchASCII(switches::kSyncNotificationMethod, "p2p"); + + // Disable non-essential access of external network resources. + if (!cl->HasSwitch(switches::kDisableBackgroundNetworking)) + cl->AppendSwitch(switches::kDisableBackgroundNetworking); +} + +void LiveSyncTest::AddOptionalTypesToCommandLine(CommandLine* cl) { + // TODO(sync): Remove this once sessions sync is enabled by default. + if (!cl->HasSwitch(switches::kEnableSyncSessions)) + cl->AppendSwitch(switches::kEnableSyncSessions); +} + +// static +Profile* LiveSyncTest::MakeProfile(const FilePath::StringType name) { + FilePath path; + PathService::Get(chrome::DIR_USER_DATA, &path); + path = path.Append(name); + + if (!file_util::PathExists(path)) + CHECK(file_util::CreateDirectory(path)); + + return Profile::CreateProfile(path); +} + +Profile* LiveSyncTest::GetProfile(int index) { + if (profiles_.empty()) + LOG(FATAL) << "SetupClients() has not yet been called."; + if (index < 0 || index >= static_cast<int>(profiles_.size())) + LOG(FATAL) << "GetProfile(): Index is out of bounds."; + return profiles_[index]; +} + +Browser* LiveSyncTest::GetBrowser(int index) { + if (browsers_.empty()) + LOG(FATAL) << "SetupClients() has not yet been called."; + if (index < 0 || index >= static_cast<int>(browsers_.size())) + LOG(FATAL) << "GetBrowser(): Index is out of bounds."; + return browsers_[index]; +} + +ProfileSyncServiceHarness* LiveSyncTest::GetClient(int index) { + if (clients_.empty()) + LOG(FATAL) << "SetupClients() has not yet been called."; + if (index < 0 || index >= static_cast<int>(clients_.size())) + LOG(FATAL) << "GetClient(): Index is out of bounds."; + return clients_[index]; +} + +Profile* LiveSyncTest::verifier() { + if (verifier_.get() == NULL) + LOG(FATAL) << "SetupClients() has not yet been called."; + return verifier_.get(); +} + +void LiveSyncTest::DisableVerifier() { + use_verifier_ = false; +} + +bool LiveSyncTest::SetupClients() { + if (num_clients_ <= 0) + LOG(FATAL) << "num_clients_ incorrectly initialized."; + if (!profiles_.empty() || !browsers_.empty() || !clients_.empty()) + LOG(FATAL) << "SetupClients() has already been called."; + + // Start up a sync test server if one is needed. + SetUpTestServerIfRequired(); + + // Create the required number of sync profiles, browsers and clients. + for (int i = 0; i < num_clients_; ++i) { + profiles_.push_back(MakeProfile( + base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), i))); + EXPECT_FALSE(GetProfile(i) == NULL) << "GetProfile(" << i << ") failed."; + + browsers_.push_back(Browser::Create(GetProfile(i))); + EXPECT_FALSE(GetBrowser(i) == NULL) << "GetBrowser(" << i << ") failed."; + + clients_.push_back( + new ProfileSyncServiceHarness(GetProfile(i), username_, password_)); + EXPECT_FALSE(GetClient(i) == NULL) << "GetClient(" << i << ") failed."; + + ui_test_utils::WaitForBookmarkModelToLoad( + GetProfile(i)->GetBookmarkModel()); + } + + // Create the verifier profile. + verifier_.reset(MakeProfile(FILE_PATH_LITERAL("Verifier"))); + ui_test_utils::WaitForBookmarkModelToLoad(verifier()->GetBookmarkModel()); + return (verifier_.get() != NULL); +} + +bool LiveSyncTest::SetupSync() { + // Create sync profiles and clients if they haven't already been created. + if (profiles_.empty()) { + if (!SetupClients()) + LOG(FATAL) << "SetupClients() failed."; + } + + // Sync each of the profiles. + for (int i = 0; i < num_clients_; ++i) { + if (!GetClient(i)->SetupSync()) + LOG(FATAL) << "SetupSync() failed."; + } + + return true; +} + +void LiveSyncTest::CleanUpOnMainThread() { + // Close all browser windows. + BrowserList::CloseAllBrowsers(); + ui_test_utils::RunAllPendingInMessageLoop(); + + // All browsers should be closed at this point, or else we could see memory + // corruption in QuitBrowser(). + CHECK_EQ(0U, BrowserList::size()); + + profiles_.reset(); + clients_.reset(); + verifier_.reset(NULL); +} + +void LiveSyncTest::SetUpInProcessBrowserTestFixture() { + // We don't take a reference to |resolver|, but mock_host_resolver_override_ + // does, so effectively assumes ownership. + net::RuleBasedHostResolverProc* resolver = + new net::RuleBasedHostResolverProc(host_resolver()); + resolver->AllowDirectLookup("*.google.com"); + // On Linux, we use Chromium's NSS implementation which uses the following + // hosts for certificate verification. Without these overrides, running the + // integration tests on Linux causes error as we make external DNS lookups. + resolver->AllowDirectLookup("*.thawte.com"); + resolver->AllowDirectLookup("*.geotrust.com"); + resolver->AllowDirectLookup("*.gstatic.com"); + mock_host_resolver_override_.reset( + new net::ScopedDefaultHostResolverProc(resolver)); +} + +void LiveSyncTest::TearDownInProcessBrowserTestFixture() { + mock_host_resolver_override_.reset(); +} + +void LiveSyncTest::ReadPasswordFile() { + CommandLine* cl = CommandLine::ForCurrentProcess(); + password_file_ = cl->GetSwitchValuePath(switches::kPasswordFileForTest); + if (password_file_.empty()) + LOG(FATAL) << "Can't run live server test without specifying --" + << switches::kPasswordFileForTest << "=<filename>"; + std::string file_contents; + file_util::ReadFileToString(password_file_, &file_contents); + ASSERT_NE(file_contents, "") << "Password file \"" + << password_file_.value() << "\" does not exist."; + std::vector<std::string> tokens; + std::string delimiters = "\r\n"; + Tokenize(file_contents, delimiters, &tokens); + ASSERT_EQ(2U, tokens.size()) << "Password file \"" + << password_file_.value() + << "\" must contain exactly two lines of text."; + username_ = tokens[0]; + password_ = tokens[1]; +} + +void LiveSyncTest::SetupMockGaiaResponses() { + username_ = "user@gmail.com"; + password_ = "password"; + factory_.reset(new URLFetcherFactory()); + fake_factory_.reset(new FakeURLFetcherFactory(factory_.get())); + fake_factory_->SetFakeResponse(kClientLoginUrl, "SID=sid\nLSID=lsid", true); + fake_factory_->SetFakeResponse(kGetUserInfoUrl, "email=user@gmail.com", true); + fake_factory_->SetFakeResponse(kIssueAuthTokenUrl, "auth", true); + fake_factory_->SetFakeResponse(kSearchDomainCheckUrl, ".google.com", true); +} + +// Start up a local sync server based on the value of server_type_, which +// was determined from the command line parameters. +void LiveSyncTest::SetUpTestServerIfRequired() { + if (server_type_ == LOCAL_PYTHON_SERVER) { + if (!SetUpLocalPythonTestServer()) + LOG(FATAL) << "Failed to set up local python sync and XMPP servers"; + } else if (server_type_ == LOCAL_LIVE_SERVER) { + // Using mock gaia credentials requires the use of a mock XMPP server. + if (username_ == "user@gmail.com" && !SetUpLocalPythonTestServer()) + LOG(FATAL) << "Failed to set up local python XMPP server"; + if (!SetUpLocalTestServer()) + LOG(FATAL) << "Failed to set up local test server"; + } else if (server_type_ == EXTERNAL_LIVE_SERVER) { + // Nothing to do; we'll just talk to the URL we were given. + } else { + LOG(FATAL) << "Don't know which server environment to run test in."; + } +} + +bool LiveSyncTest::SetUpLocalPythonTestServer() { + EXPECT_TRUE(sync_server_.Start()) + << "Could not launch local python test server."; + + CommandLine* cl = CommandLine::ForCurrentProcess(); + if (server_type_ == LOCAL_PYTHON_SERVER) { + std::string sync_service_url = sync_server_.GetURL("chromiumsync").spec(); + cl->AppendSwitchASCII(switches::kSyncServiceURL, sync_service_url); + VLOG(1) << "Started local python sync server at " << sync_service_url; + } + + int xmpp_port = 0; + if (!sync_server_.server_data().GetInteger("xmpp_port", &xmpp_port)) { + LOG(ERROR) << "Could not find valid xmpp_port value"; + return false; + } + if ((xmpp_port <= 0) || (xmpp_port > kuint16max)) { + LOG(ERROR) << "Invalid xmpp port: " << xmpp_port; + return false; + } + + net::HostPortPair xmpp_host_port_pair(sync_server_.host_port_pair()); + xmpp_host_port_pair.set_port(xmpp_port); + xmpp_port_.reset(new net::ScopedPortException(xmpp_port)); + + if (!cl->HasSwitch(switches::kSyncNotificationHost)) { + cl->AppendSwitchASCII(switches::kSyncNotificationHost, + xmpp_host_port_pair.ToString()); + // The local XMPP server only supports insecure connections. + cl->AppendSwitch(switches::kSyncAllowInsecureXmppConnection); + } + VLOG(1) << "Started local python XMPP server at " + << xmpp_host_port_pair.ToString(); + + return true; +} + +bool LiveSyncTest::SetUpLocalTestServer() { + CommandLine* cl = CommandLine::ForCurrentProcess(); + CommandLine::StringType server_cmdline_string = cl->GetSwitchValueNative( + switches::kSyncServerCommandLine); + CommandLine::StringVector server_cmdline_vector; + CommandLine::StringType delimiters(FILE_PATH_LITERAL(" ")); + Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector); + CommandLine server_cmdline(server_cmdline_vector); + base::LaunchOptions options; +#if defined(OS_WIN) + options.start_hidden = true; +#endif + if (!base::LaunchProcess(server_cmdline, options, &test_server_handle_)) + LOG(ERROR) << "Could not launch local test server."; + + const int kMaxWaitTime = TestTimeouts::action_max_timeout_ms(); + const int kNumIntervals = 15; + if (WaitForTestServerToStart(kMaxWaitTime, kNumIntervals)) { + VLOG(1) << "Started local test server at " + << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << "."; + return true; + } else { + LOG(ERROR) << "Could not start local test server at " + << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << "."; + return false; + } +} + +bool LiveSyncTest::TearDownLocalPythonTestServer() { + if (!sync_server_.Stop()) { + LOG(ERROR) << "Could not stop local python test server."; + return false; + } + xmpp_port_.reset(); + return true; +} + +bool LiveSyncTest::TearDownLocalTestServer() { + if (test_server_handle_ != base::kNullProcessHandle) { + EXPECT_TRUE(base::KillProcess(test_server_handle_, 0, false)) + << "Could not stop local test server."; + base::CloseProcessHandle(test_server_handle_); + test_server_handle_ = base::kNullProcessHandle; + } + return true; +} + +bool LiveSyncTest::WaitForTestServerToStart(int time_ms, int intervals) { + for (int i = 0; i < intervals; ++i) { + if (IsTestServerRunning()) + return true; + base::PlatformThread::Sleep(time_ms / intervals); + } + return false; +} + +bool LiveSyncTest::IsTestServerRunning() { + CommandLine* cl = CommandLine::ForCurrentProcess(); + std::string sync_url = cl->GetSwitchValueASCII(switches::kSyncServiceURL); + GURL sync_url_status(sync_url.append("/healthz")); + SyncServerStatusChecker delegate; + URLFetcher fetcher(sync_url_status, URLFetcher::GET, &delegate); + fetcher.set_request_context(Profile::Deprecated::GetDefaultRequestContext()); + fetcher.Start(); + ui_test_utils::RunMessageLoop(); + return delegate.running(); +} + +void LiveSyncTest::EnableNetwork(Profile* profile) { + SetProxyConfig(profile->GetRequestContext(), + net::ProxyConfig::CreateDirect()); + // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed. + net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); +} + +void LiveSyncTest::DisableNetwork(Profile* profile) { + // Set the current proxy configuration to a nonexistent proxy to effectively + // disable networking. + net::ProxyConfig config; + config.proxy_rules().ParseFromString("http=127.0.0.1:0"); + SetProxyConfig(profile->GetRequestContext(), config); + // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed. + net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); +} + +bool LiveSyncTest::EnableEncryption(int index, syncable::ModelType type) { + return GetClient(index)->EnableEncryptionForType(type); +} + +bool LiveSyncTest::IsEncrypted(int index, syncable::ModelType type) { + return GetClient(index)->IsTypeEncrypted(type); +} + +bool LiveSyncTest::AwaitQuiescence() { + return ProfileSyncServiceHarness::AwaitQuiescence(clients()); +} + +bool LiveSyncTest::ServerSupportsNotificationControl() const { + EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_); + + // Supported only if we're using the python testserver. + return server_type_ == LOCAL_PYTHON_SERVER; +} + +void LiveSyncTest::DisableNotifications() { + ASSERT_TRUE(ServerSupportsNotificationControl()); + std::string path = "chromiumsync/disablenotifications"; + ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); + ASSERT_EQ("Notifications disabled", + UTF16ToASCII(browser()->GetSelectedTabContents()->GetTitle())); +} + +void LiveSyncTest::EnableNotifications() { + ASSERT_TRUE(ServerSupportsNotificationControl()); + std::string path = "chromiumsync/enablenotifications"; + ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); + ASSERT_EQ("Notifications enabled", + UTF16ToASCII(browser()->GetSelectedTabContents()->GetTitle())); +} + +void LiveSyncTest::TriggerNotification( + const syncable::ModelTypeSet& changed_types) { + ASSERT_TRUE(ServerSupportsNotificationControl()); + const std::string& data = + sync_notifier::P2PNotificationData("from_server", + sync_notifier::NOTIFY_ALL, + changed_types).ToString(); + const std::string& path = + std::string("chromiumsync/sendnotification?channel=") + + sync_notifier::kSyncP2PNotificationChannel + "&data=" + data; + ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); + ASSERT_EQ("Notification sent", + UTF16ToASCII(browser()->GetSelectedTabContents()->GetTitle())); +} + +bool LiveSyncTest::ServerSupportsErrorTriggering() const { + EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_); + + // Supported only if we're using the python testserver. + return server_type_ == LOCAL_PYTHON_SERVER; +} + +void LiveSyncTest::TriggerMigrationDoneError( + const syncable::ModelTypeSet& model_types) { + ASSERT_TRUE(ServerSupportsErrorTriggering()); + std::string path = "chromiumsync/migrate"; + char joiner = '?'; + for (syncable::ModelTypeSet::const_iterator it = model_types.begin(); + it != model_types.end(); ++it) { + path.append(base::StringPrintf("%ctype=%d", joiner, + syncable::GetExtensionFieldNumberFromModelType(*it))); + joiner = '&'; + } + ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); + ASSERT_EQ("Migration: 200", + UTF16ToASCII(browser()->GetSelectedTabContents()->GetTitle())); +} + +void LiveSyncTest::TriggerBirthdayError() { + ASSERT_TRUE(ServerSupportsErrorTriggering()); + std::string path = "chromiumsync/birthdayerror"; + ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); + ASSERT_EQ("Birthday error", + UTF16ToASCII(browser()->GetSelectedTabContents()->GetTitle())); +} + +void LiveSyncTest::TriggerTransientError() { + ASSERT_TRUE(ServerSupportsErrorTriggering()); + std::string path = "chromiumsync/transienterror"; + ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); + ASSERT_EQ("Transient error", + UTF16ToASCII(browser()->GetSelectedTabContents()->GetTitle())); +} + +void LiveSyncTest::TriggerSetSyncTabs() { + ASSERT_TRUE(ServerSupportsErrorTriggering()); + std::string path = "chromiumsync/synctabs"; + ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path)); + ASSERT_EQ("Sync Tabs", + UTF16ToASCII(browser()->GetSelectedTabContents()->GetTitle())); +} + +void LiveSyncTest::SetProxyConfig(net::URLRequestContextGetter* context_getter, + const net::ProxyConfig& proxy_config) { + base::WaitableEvent done(false, false); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + new SetProxyConfigTask(&done, + context_getter, + proxy_config)); + done.Wait(); +} diff --git a/chrome/browser/sync/test/live_sync/live_sync_test.h b/chrome/browser/sync/test/live_sync/live_sync_test.h new file mode 100644 index 0000000..2769510c --- /dev/null +++ b/chrome/browser/sync/test/live_sync/live_sync_test.h @@ -0,0 +1,317 @@ +// Copyright (c) 2011 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_LIVE_SYNC_LIVE_SYNC_TEST_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_LIVE_SYNC_TEST_H_ +#pragma once + +#include "chrome/test/base/in_process_browser_test.h" + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/file_util.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/process_util.h" +#include "chrome/browser/sync/syncable/model_type.h" +#include "net/base/mock_host_resolver.h" +#include "net/test/test_server.h" + +class CommandLine; +class Profile; +class ProfileSyncServiceHarness; +class FakeURLFetcherFactory; +class URLFetcherFactory; + +namespace net { +class ProxyConfig; +class ScopedDefaultHostResolverProc; +class URLRequestContextGetter; +} + +// This is the base class for integration tests for all sync data types. Derived +// classes must be defined for each sync data type. Individual tests are defined +// using the IN_PROC_BROWSER_TEST_F macro. +class LiveSyncTest : public InProcessBrowserTest { + public: + // The different types of live sync tests that can be implemented. + enum TestType { + // Tests where only one client profile is synced with the server. Typically + // sanity level tests. + SINGLE_CLIENT, + + // Tests where two client profiles are synced with the server. Typically + // functionality level tests. + TWO_CLIENT, + + // Tests where three or more client profiles are synced with the server. + // Typically, these tests create client side races and verify that sync + // works. + MULTIPLE_CLIENT, + + // Tests where several client profiles are synced with the server. Only used + // by stress tests. + MANY_CLIENT + }; + + // The type of server we're running against. + enum ServerType { + SERVER_TYPE_UNDECIDED, + LOCAL_PYTHON_SERVER, // The mock python server that runs locally and is + // part of the Chromium checkout. + LOCAL_LIVE_SERVER, // Some other server (maybe the real binary used by + // Google's sync service) that can be started on + // a per-test basis by running a command + EXTERNAL_LIVE_SERVER, // A remote server that the test code has no control + // over whatsoever; cross your fingers that the + // account state is initially clean. + }; + + // A LiveSyncTest must be associated with a particular test type. + explicit LiveSyncTest(TestType test_type); + + virtual ~LiveSyncTest(); + + // Validates command line parameters and creates a local python test server if + // specified. + virtual void SetUp() OVERRIDE; + + // Brings down local python test server if one was created. + virtual void TearDown() OVERRIDE; + + // Sets up command line flags required for sync tests. + virtual void SetUpCommandLine(CommandLine* cl) OVERRIDE; + + // Used to get the number of sync clients used by a test. + int num_clients() WARN_UNUSED_RESULT { return num_clients_; } + + // Returns a pointer to a particular sync profile. Callee owns the object + // and manages its lifetime. + Profile* GetProfile(int index) WARN_UNUSED_RESULT; + + // Returns a pointer to a particular browser. Callee owns the object + // and manages its lifetime. + Browser* GetBrowser(int index) WARN_UNUSED_RESULT; + + // Returns a pointer to a particular sync client. Callee owns the object + // and manages its lifetime. + ProfileSyncServiceHarness* GetClient(int index) WARN_UNUSED_RESULT; + + // Returns a reference to the collection of sync clients. Callee owns the + // object and manages its lifetime. + std::vector<ProfileSyncServiceHarness*>& clients() WARN_UNUSED_RESULT { + return clients_.get(); + } + + // Returns a pointer to the sync profile that is used to verify changes to + // individual sync profiles. Callee owns the object and manages its lifetime. + Profile* verifier() WARN_UNUSED_RESULT; + + // Used to determine whether the verifier profile should be updated or not. + bool use_verifier() WARN_UNUSED_RESULT { return use_verifier_; } + + // After calling this method, changes made to a profile will no longer be + // reflected in the verifier profile. Note: Not all datatypes use this. + // TODO(rsimha): Hook up all datatypes to this mechanism. + void DisableVerifier(); + + // Initializes sync clients and profiles but does not sync any of them. + virtual bool SetupClients() WARN_UNUSED_RESULT; + + // Initializes sync clients and profiles if required and syncs each of them. + virtual bool SetupSync() WARN_UNUSED_RESULT; + + // Enable outgoing network connections for the given profile. + virtual void EnableNetwork(Profile* profile); + + // Disable outgoing network connections for the given profile. + virtual void DisableNetwork(Profile* profile); + + // Encrypts the datatype |type| for profile |index|. + bool EnableEncryption(int index, syncable::ModelType type); + + // Checks if the datatype |type| is encrypted for profile |index|. + bool IsEncrypted(int index, syncable::ModelType type); + + // Blocks until all sync clients have completed their mutual sync cycles. + // Returns true if a quiescent state was successfully reached. + bool AwaitQuiescence(); + + // Returns true if the server being used supports controlling + // notifications. + bool ServerSupportsNotificationControl() const; + + // Disable notifications on the server. This operation is available + // only if ServerSupportsNotificationControl() returned true. + void DisableNotifications(); + + // Enable notifications on the server. This operation is available + // only if ServerSupportsNotificationControl() returned true. + void EnableNotifications(); + + // Trigger a notification to be sent to all clients. This operation + // is available only if ServerSupportsNotificationControl() returned + // true. + void TriggerNotification(const syncable::ModelTypeSet& changed_types); + + // Returns true if the server being used supports injecting errors. + bool ServerSupportsErrorTriggering() const; + + // Triggers a migration for one or more datatypes, and waits + // for the server to complete it. This operation is available + // only if ServerSupportsErrorTriggering() returned true. + void TriggerMigrationDoneError(const syncable::ModelTypeSet& model_types); + + // Triggers the server to set its birthday to a random value thereby + // the server would return a birthday error on next sync. + void TriggerBirthdayError(); + + // Triggers a transient error on the server. Note the server will stay in + // this state until shut down. + void TriggerTransientError(); + + // Triggers setting the sync_tabs field of the nigori node. + void TriggerSetSyncTabs(); + + protected: + // Add custom switches needed for running the test. + virtual void AddTestSwitches(CommandLine* cl); + + // Append the command line switches to enable experimental types that aren't + // on by default yet. + virtual void AddOptionalTypesToCommandLine(CommandLine* cl); + + // InProcessBrowserTest override. Destroys all the sync clients and sync + // profiles created by a test. + virtual void CleanUpOnMainThread() OVERRIDE; + + // InProcessBrowserTest override. Changes behavior of the default host + // resolver to avoid DNS lookup errors. + virtual void SetUpInProcessBrowserTestFixture() OVERRIDE; + + // InProcessBrowserTest override. Resets the host resolver its default + // behavior. + virtual void TearDownInProcessBrowserTestFixture() OVERRIDE; + + // GAIA account used by the test case. + std::string username_; + + // GAIA password used by the test case. + std::string password_; + + // Locally available plain text file in which GAIA credentials are stored. + FilePath password_file_; + + private: + // Helper to ProfileManager::CreateProfile that handles path creation. + static Profile* MakeProfile(const FilePath::StringType name); + + // Helper method used to read GAIA credentials from a local password file + // specified via the "--password-file-for-test" command line switch. + // Note: The password file must be a plain text file with exactly two lines -- + // the username on the first line and the password on the second line. + void ReadPasswordFile(); + + // Helper method that starts up a sync test server if required. + void SetUpTestServerIfRequired(); + + // Helper method used to start up a local python test server. Note: We set up + // an XMPP-only python server if |server_type_| is LOCAL_LIVE_SERVER and mock + // gaia credentials are in use. Returns true if successful. + bool SetUpLocalPythonTestServer(); + + // Helper method used to start up a local sync test server. Returns true if + // successful. + bool SetUpLocalTestServer(); + + // Helper method used to destroy the local python sync test server if one was + // created. Returns true if successful. + bool TearDownLocalPythonTestServer(); + + // Helper method used to destroy the local sync test server if one was + // created. Returns true if successful. + bool TearDownLocalTestServer(); + + // Helper method that waits for up to |time_ms| milliseconds for the test + // server to start. Splits the time into |intervals| intervals, and polls the + // server after each interval to see if it has started. Returns true if + // successful. + bool WaitForTestServerToStart(int time_ms, int intervals); + + // Helper method used to check if the test server is up and running. + bool IsTestServerRunning(); + + // Used to disable and enable network connectivity by providing and + // clearing an invalid proxy configuration. + void SetProxyConfig(net::URLRequestContextGetter* context, + const net::ProxyConfig& proxy_config); + + // Helper method used to set up fake responses for kClientLoginUrl, + // kIssueAuthTokenUrl, kGetUserInfoUrl and kSearchDomainCheckUrl in order to + // mock out calls to GAIA servers. + void SetupMockGaiaResponses(); + + // Test server of type sync, started on demand. + net::TestServer sync_server_; + + // Helper class to whitelist the notification port. + scoped_ptr<net::ScopedPortException> xmpp_port_; + + // Used to differentiate between single-client, two-client, multi-client and + // many-client tests. + TestType test_type_; + + // Tells us what kind of server we're using (some tests run only on certain + // server types). + ServerType server_type_; + + // Number of sync clients that will be created by a test. + int num_clients_; + + // Collection of sync profiles used by a test. A sync profile maintains sync + // data contained within its own subdirectory under the chrome user data + // directory. + ScopedVector<Profile> profiles_; + + // Collection of pointers to the browser objects used by a test. One browser + // instance is created for each sync profile. Browser object lifetime is + // managed by BrowserList, so we don't use a ScopedVector here. + std::vector<Browser*> browsers_; + + // Collection of sync clients used by a test. A sync client is associated with + // a sync profile, and implements methods that sync the contents of the + // profile with the server. + ScopedVector<ProfileSyncServiceHarness> clients_; + + // Sync profile against which changes to individual profiles are verified. We + // don't need a corresponding verifier sync client because the contents of the + // verifier profile are strictly local, and are not meant to be synced. + scoped_ptr<Profile> verifier_; + + // Indicates whether changes to a profile should also change the verifier + // profile or not. + bool use_verifier_; + + // Sync integration tests need to make live DNS requests for access to + // GAIA and sync server URLs under google.com. We use a scoped version + // to override the default resolver while the test is active. + scoped_ptr<net::ScopedDefaultHostResolverProc> mock_host_resolver_override_; + + // Used to start and stop the local test server. + base::ProcessHandle test_server_handle_; + + // Fake URLFetcher factory used to mock out GAIA signin. + scoped_ptr<FakeURLFetcherFactory> fake_factory_; + + // The URLFetcherFactory instance used to instantiate |fake_factory_|. + scoped_ptr<URLFetcherFactory> factory_; + + DISALLOW_COPY_AND_ASSIGN(LiveSyncTest); +}; + +DISABLE_RUNNABLE_METHOD_REFCOUNT(LiveSyncTest); + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_LIVE_SYNC_TEST_H_ diff --git a/chrome/browser/sync/test/live_sync/many_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/live_sync/many_client_bookmarks_sync_test.cc new file mode 100644 index 0000000..9b87fae --- /dev/null +++ b/chrome/browser/sync/test/live_sync/many_client_bookmarks_sync_test.cc @@ -0,0 +1,28 @@ +// Copyright (c) 2011 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/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/bookmarks_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using bookmarks_helper::AddURL; +using bookmarks_helper::AllModelsMatch; + +class ManyClientBookmarksSyncTest : public LiveSyncTest { + public: + ManyClientBookmarksSyncTest() : LiveSyncTest(MANY_CLIENT) {} + virtual ~ManyClientBookmarksSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ManyClientBookmarksSyncTest); +}; + +// TODO(rsimha): Enable once http://crbug.com/69604 is fixed. +IN_PROC_BROWSER_TEST_F(ManyClientBookmarksSyncTest, DISABLED_Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AddURL(0, L"Google URL", GURL("http://www.google.com/")) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitGroupSyncCycleCompletion(clients())); + ASSERT_TRUE(AllModelsMatch()); +} diff --git a/chrome/browser/sync/test/live_sync/many_client_passwords_sync_test.cc b/chrome/browser/sync/test/live_sync/many_client_passwords_sync_test.cc new file mode 100644 index 0000000..e701cc9 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/many_client_passwords_sync_test.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2011 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/utf_string_conversions.h" +#include "chrome/browser/password_manager/password_form_data.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/passwords_helper.h" + +using passwords_helper::AddLogin; +using passwords_helper::AllProfilesContainSamePasswordFormsAsVerifier; +using passwords_helper::CreateTestPasswordForm; +using passwords_helper::GetPasswordCount; +using passwords_helper::GetPasswordStore; +using passwords_helper::GetVerifierPasswordCount; +using passwords_helper::GetVerifierPasswordStore; + +using webkit_glue::PasswordForm; + +class ManyClientPasswordsSyncTest : public LiveSyncTest { + public: + ManyClientPasswordsSyncTest() : LiveSyncTest(MANY_CLIENT) {} + virtual ~ManyClientPasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ManyClientPasswordsSyncTest); +}; + +// TODO(rsimha): Enable once http://crbug.com/69604 is fixed. +IN_PROC_BROWSER_TEST_F(ManyClientPasswordsSyncTest, DISABLED_Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + PasswordForm form = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form); + ASSERT_EQ(1, GetVerifierPasswordCount()); + AddLogin(GetPasswordStore(0), form); + ASSERT_EQ(1, GetPasswordCount(0)); + ASSERT_TRUE(GetClient(0)->AwaitGroupSyncCycleCompletion(clients())); + + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + ASSERT_EQ(1, GetPasswordCount(0)); +} diff --git a/chrome/browser/sync/test/live_sync/many_client_preferences_sync_test.cc b/chrome/browser/sync/test/live_sync/many_client_preferences_sync_test.cc new file mode 100644 index 0000000..a66b979 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/many_client_preferences_sync_test.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/preferences_helper.h" +#include "chrome/common/pref_names.h" + +using preferences_helper::BooleanPrefMatches; +using preferences_helper::ChangeBooleanPref; + +class ManyClientPreferencesSyncTest : public LiveSyncTest { + public: + ManyClientPreferencesSyncTest() : LiveSyncTest(MANY_CLIENT) {} + virtual ~ManyClientPreferencesSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ManyClientPreferencesSyncTest); +}; + +// TODO(rsimha): Enable once http://crbug.com/69604 is fixed. +IN_PROC_BROWSER_TEST_F(ManyClientPreferencesSyncTest, DISABLED_Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kHomePageIsNewTabPage)); + ChangeBooleanPref(0, prefs::kHomePageIsNewTabPage); + ASSERT_TRUE(GetClient(0)->AwaitGroupSyncCycleCompletion(clients())); + ASSERT_TRUE(BooleanPrefMatches(prefs::kHomePageIsNewTabPage)); +} diff --git a/chrome/browser/sync/test/live_sync/migration_errors_test.cc b/chrome/browser/sync/test/live_sync/migration_errors_test.cc new file mode 100644 index 0000000..febefc8 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/migration_errors_test.cc @@ -0,0 +1,453 @@ +// Copyright (c) 2011 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. + +// TODO(akalin): Rename this file to migration_test.cc. + +#include "chrome/browser/prefs/scoped_user_pref_update.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/bookmarks_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/preferences_helper.h" +#include "chrome/browser/translate/translate_prefs.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/ui_test_utils.h" + +using bookmarks_helper::AddURL; +using bookmarks_helper::IndexedURL; +using bookmarks_helper::IndexedURLTitle; + +using preferences_helper::BooleanPrefMatches; +using preferences_helper::ChangeBooleanPref; + +namespace { + +// Utility functions to make a model type set out of a small number of +// model types. + +syncable::ModelTypeSet MakeSet(syncable::ModelType type) { + syncable::ModelTypeSet model_types; + model_types.insert(type); + return model_types; +} + +syncable::ModelTypeSet MakeSet(syncable::ModelType type1, + syncable::ModelType type2) { + syncable::ModelTypeSet model_types; + model_types.insert(type1); + model_types.insert(type2); + return model_types; +} + +// An ordered list of model types sets to migrate. Used by +// RunMigrationTest(). +typedef std::deque<syncable::ModelTypeSet> MigrationList; + +// Utility functions to make a MigrationList out of a small number of +// model types / model type sets. + +MigrationList MakeList(const syncable::ModelTypeSet& model_types) { + return MigrationList(1, model_types); +} + +MigrationList MakeList(const syncable::ModelTypeSet& model_types1, + const syncable::ModelTypeSet& model_types2) { + MigrationList migration_list; + migration_list.push_back(model_types1); + migration_list.push_back(model_types2); + return migration_list; +} + +MigrationList MakeList(syncable::ModelType type) { + return MakeList(MakeSet(type)); +} + +MigrationList MakeList(syncable::ModelType type1, + syncable::ModelType type2) { + return MakeList(MakeSet(type1), MakeSet(type2)); +} + +class MigrationTest : public LiveSyncTest { + public: + explicit MigrationTest(TestType test_type) : LiveSyncTest(test_type) {} + virtual ~MigrationTest() {} + + // TODO(akalin): Add more MODIFY_(data type) trigger methods, as + // well as a poll-based trigger method. + enum TriggerMethod { MODIFY_PREF, MODIFY_BOOKMARK, TRIGGER_NOTIFICATION }; + + syncable::ModelTypeSet GetPreferredDataTypes() { + syncable::ModelTypeSet preferred_data_types; + GetClient(0)->service()->GetPreferredDataTypes(&preferred_data_types); + // Make sure all clients have the same preferred data types. + for (int i = 1; i < num_clients(); ++i) { + syncable::ModelTypeSet other_preferred_data_types; + GetClient(i)->service()->GetPreferredDataTypes( + &other_preferred_data_types); + EXPECT_EQ(preferred_data_types, other_preferred_data_types); + } + return preferred_data_types; + } + + // Returns a MigrationList with every enabled data type in its own + // set. + MigrationList GetPreferredDataTypesList() { + MigrationList migration_list; + const syncable::ModelTypeSet& preferred_data_types = + GetPreferredDataTypes(); + for (syncable::ModelTypeSet::const_iterator it = + preferred_data_types.begin(); + it != preferred_data_types.end(); ++it) { + migration_list.push_back(MakeSet(*it)); + } + return migration_list; + } + + // Trigger a migration for the given types with the given method. + void TriggerMigration(const syncable::ModelTypeSet& model_types, + TriggerMethod trigger_method) { + switch (trigger_method) { + case MODIFY_PREF: + // Unlike MODIFY_BOOKMARK, MODIFY_PREF doesn't cause a + // notification to happen (since model association on a + // boolean pref clobbers the local value), so it doesn't work + // for anything but single-client tests. + ASSERT_EQ(1, num_clients()); + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); + ChangeBooleanPref(0, prefs::kShowHomeButton); + break; + case MODIFY_BOOKMARK: + ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0)))); + break; + case TRIGGER_NOTIFICATION: + TriggerNotification(model_types); + break; + default: + ADD_FAILURE(); + } + } + + // Block until all clients have completed migration for the given + // types. + void AwaitMigration(const syncable::ModelTypeSet& migrate_types) { + for (int i = 0; i < num_clients(); ++i) { + ASSERT_TRUE(GetClient(i)->AwaitMigration(migrate_types)); + } + } + + bool ShouldRunMigrationTest() const { + if (!ServerSupportsNotificationControl() || + !ServerSupportsErrorTriggering()) { + LOG(WARNING) << "Test skipped in this server environment."; + return false; + } + return true; + } + + // Makes sure migration works with the given migration list and + // trigger method. + void RunMigrationTest(const MigrationList& migration_list, + TriggerMethod trigger_method) { + ASSERT_TRUE(ShouldRunMigrationTest()); + + // If we have only one client, turn off notifications to avoid the + // possibility of spurious sync cycles. + bool do_test_without_notifications = + (trigger_method != TRIGGER_NOTIFICATION && num_clients() == 1); + + if (do_test_without_notifications) { + DisableNotifications(); + } + + // Phase 1: Trigger the migrations on the server. + for (MigrationList::const_iterator it = migration_list.begin(); + it != migration_list.end(); ++it) { + TriggerMigrationDoneError(*it); + } + + // Phase 2: Trigger each migration individually and wait for it to + // complete. (Multiple migrations may be handled by each + // migration cycle, but there's no guarantee of that, so we have + // to trigger each migration individually.) + for (MigrationList::const_iterator it = migration_list.begin(); + it != migration_list.end(); ++it) { + TriggerMigration(*it, trigger_method); + AwaitMigration(*it); + } + + // Phase 3: Wait for all clients to catch up. + AwaitQuiescence(); + + // Re-enable notifications if we disabled it. + if (do_test_without_notifications) { + EnableNotifications(); + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(MigrationTest); +}; + +class MigrationSingleClientTest : public MigrationTest { + public: + MigrationSingleClientTest() : MigrationTest(SINGLE_CLIENT) {} + virtual ~MigrationSingleClientTest() {} + + void RunSingleClientMigrationTest(const MigrationList& migration_list, + TriggerMethod trigger_method) { + if (!ShouldRunMigrationTest()) { + return; + } + ASSERT_TRUE(SetupSync()); + RunMigrationTest(migration_list, trigger_method); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MigrationSingleClientTest); +}; + +// The simplest possible migration tests -- a single data type. + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyPref) { + RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), MODIFY_PREF); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsOnlyModifyBookmark) { + RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), + MODIFY_BOOKMARK); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, + PrefsOnlyTriggerNotification) { + RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), + TRIGGER_NOTIFICATION); +} + +// Nigori is handled specially, so we test that separately. + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, NigoriOnly) { + RunSingleClientMigrationTest(MakeList(syncable::PREFERENCES), + TRIGGER_NOTIFICATION); +} + +// A little more complicated -- two data types. + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, + BookmarksPrefsIndividually) { + RunSingleClientMigrationTest( + MakeList(syncable::BOOKMARKS, syncable::PREFERENCES), + MODIFY_PREF); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, BookmarksPrefsBoth) { + RunSingleClientMigrationTest( + MakeList(MakeSet(syncable::BOOKMARKS, syncable::PREFERENCES)), + MODIFY_BOOKMARK); +} + +// Two data types with one being nigori. + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriIndividiaully) { + RunSingleClientMigrationTest( + MakeList(syncable::PREFERENCES, syncable::NIGORI), + TRIGGER_NOTIFICATION); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, PrefsNigoriBoth) { + RunSingleClientMigrationTest( + MakeList(MakeSet(syncable::PREFERENCES, syncable::NIGORI)), + MODIFY_PREF); +} + +// The whole shebang -- all data types. + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesIndividually) { + ASSERT_TRUE(SetupClients()); + RunSingleClientMigrationTest(GetPreferredDataTypesList(), MODIFY_BOOKMARK); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, + AllTypesIndividuallyTriggerNotification) { + ASSERT_TRUE(SetupClients()); + RunSingleClientMigrationTest(GetPreferredDataTypesList(), + TRIGGER_NOTIFICATION); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesAtOnce) { + ASSERT_TRUE(SetupClients()); + RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()), + MODIFY_PREF); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, + AllTypesAtOnceTriggerNotification) { + ASSERT_TRUE(SetupClients()); + RunSingleClientMigrationTest(MakeList(GetPreferredDataTypes()), + TRIGGER_NOTIFICATION); +} + +// All data types plus nigori. + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, + AllTypesWithNigoriIndividually) { + ASSERT_TRUE(SetupClients()); + MigrationList migration_list = GetPreferredDataTypesList(); + migration_list.push_front(MakeSet(syncable::NIGORI)); + RunSingleClientMigrationTest(migration_list, MODIFY_BOOKMARK); +} + +IN_PROC_BROWSER_TEST_F(MigrationSingleClientTest, AllTypesWithNigoriAtOnce) { + ASSERT_TRUE(SetupClients()); + syncable::ModelTypeSet all_types = GetPreferredDataTypes(); + all_types.insert(syncable::NIGORI); + RunSingleClientMigrationTest(MakeList(all_types), MODIFY_PREF); +} + +class MigrationTwoClientTest : public MigrationTest { + public: + MigrationTwoClientTest() : MigrationTest(TWO_CLIENT) {} + virtual ~MigrationTwoClientTest() {} + + // Helper function that verifies that preferences sync still works. + void VerifyPrefSync() { + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); + ChangeBooleanPref(0, prefs::kShowHomeButton); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); + } + + void RunTwoClientMigrationTest(const MigrationList& migration_list, + TriggerMethod trigger_method) { + if (!ShouldRunMigrationTest()) { + return; + } + ASSERT_TRUE(SetupSync()); + + // Make sure pref sync works before running the migration test. + VerifyPrefSync(); + + RunMigrationTest(migration_list, trigger_method); + + // Make sure pref sync still works after running the migration + // test. + VerifyPrefSync(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MigrationTwoClientTest); +}; + +// Easiest possible test of migration errors: triggers a server +// migration on one datatype, then modifies some other datatype. +IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, + MigratePrefsThenModifyBookmark) { + RunTwoClientMigrationTest(MakeList(syncable::PREFERENCES), + MODIFY_BOOKMARK); +} + +// Triggers a server migration on two datatypes, then makes a local +// modification to one of them. +IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, + MigratePrefsAndBookmarksThenModifyBookmark) { + RunTwoClientMigrationTest( + MakeList(syncable::PREFERENCES, syncable::BOOKMARKS), + MODIFY_BOOKMARK); +} + +// Migrate every datatype in sequence; the catch being that the server +// will only tell the client about the migrations one at a time. +IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigrationHellWithoutNigori) { + ASSERT_TRUE(SetupClients()); + MigrationList migration_list = GetPreferredDataTypesList(); + // Let the first nudge be a datatype that's neither prefs nor + // bookmarks. + migration_list.push_front(MakeSet(syncable::THEMES)); + RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK); +} + +IN_PROC_BROWSER_TEST_F(MigrationTwoClientTest, MigrationHellWithNigori) { + ASSERT_TRUE(SetupClients()); + MigrationList migration_list = GetPreferredDataTypesList(); + // Let the first nudge be a datatype that's neither prefs nor + // bookmarks. + migration_list.push_front(MakeSet(syncable::THEMES)); + // Pop off one so that we don't migrate all data types; the syncer + // freaks out if we do that (see http://crbug.com/94882). + ASSERT_GE(migration_list.size(), 2u); + ASSERT_NE(migration_list.back(), MakeSet(syncable::NIGORI)); + migration_list.back() = MakeSet(syncable::NIGORI); + RunTwoClientMigrationTest(migration_list, MODIFY_BOOKMARK); +} + +class MigrationReconfigureTest : public MigrationTwoClientTest { + public: + MigrationReconfigureTest() {} + + virtual void SetUpCommandLine(CommandLine* cl) OVERRIDE { + AddTestSwitches(cl); + // Do not add optional datatypes. + } + + virtual ~MigrationReconfigureTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MigrationReconfigureTest); +}; + +IN_PROC_BROWSER_TEST_F(MigrationReconfigureTest, SetSyncTabs) { + if (!ServerSupportsErrorTriggering()) { + LOG(WARNING) << "Test skipped in this server environment."; + return; + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_FALSE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); + ASSERT_FALSE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); + + // Phase 1: Before migrating anything, create & sync a preference. + VerifyPrefSync(); + + // Phase 2: Trigger setting the sync_tabs field. + TriggerSetSyncTabs(); + + // Phase 3: Modify a bookmark and wait for it to sync. + ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Phase 4: Verify that preferences can still be synchronized. + VerifyPrefSync(); + + // Phase 5: Verify that sessions are registered and enabled. + ASSERT_TRUE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); + ASSERT_TRUE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); +} + +IN_PROC_BROWSER_TEST_F(MigrationReconfigureTest, SetSyncTabsAndMigrate) { + if (!ServerSupportsErrorTriggering()) { + LOG(WARNING) << "Test skipped in this server environment."; + return; + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_FALSE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); + ASSERT_FALSE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); + + // Phase 1: Before migrating anything, create & sync a preference. + VerifyPrefSync(); + + // Phase 2: Trigger setting the sync_tabs field. + TriggerSetSyncTabs(); + + // Phase 3: Trigger a preference migration on the server. + RunMigrationTest(MakeList(syncable::PREFERENCES), MODIFY_BOOKMARK); + + // Phase 5: Verify that preferences can still be synchronized. + VerifyPrefSync(); + + // Phase 6: Verify that sessions are registered and enabled. + ASSERT_TRUE(GetClient(0)->IsTypeRegistered(syncable::SESSIONS)); + ASSERT_TRUE(GetClient(0)->IsTypePreferred(syncable::SESSIONS)); +} + +} // namespace diff --git a/chrome/browser/sync/test/live_sync/multiple_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/live_sync/multiple_client_bookmarks_sync_test.cc new file mode 100644 index 0000000..cf70e6a --- /dev/null +++ b/chrome/browser/sync/test/live_sync/multiple_client_bookmarks_sync_test.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2011 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/test/live_sync/bookmarks_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using bookmarks_helper::AddURL; +using bookmarks_helper::AllModelsMatch; + +class MultipleClientBookmarksSyncTest : public LiveSyncTest { + public: + MultipleClientBookmarksSyncTest() : LiveSyncTest(MULTIPLE_CLIENT) {} + virtual ~MultipleClientBookmarksSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MultipleClientBookmarksSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(MultipleClientBookmarksSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + for (int i = 0; i < num_clients(); ++i) { + ASSERT_TRUE(AddURL(i, base::StringPrintf(L"Google URL %d", i), + GURL(StringPrintf("http://www.google.com/%d", i))) != NULL); + } + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); +} diff --git a/chrome/browser/sync/test/live_sync/multiple_client_passwords_sync_test.cc b/chrome/browser/sync/test/live_sync/multiple_client_passwords_sync_test.cc new file mode 100644 index 0000000..d722cc2 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/multiple_client_passwords_sync_test.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2011 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 "base/utf_string_conversions.h" +#include "chrome/browser/password_manager/password_form_data.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/passwords_helper.h" + +using passwords_helper::AddLogin; +using passwords_helper::AllProfilesContainSamePasswordForms; +using passwords_helper::CreateTestPasswordForm; +using passwords_helper::GetPasswordCount; +using passwords_helper::GetPasswordStore; + +using webkit_glue::PasswordForm; + +class MultipleClientPasswordsSyncTest : public LiveSyncTest { + public: + MultipleClientPasswordsSyncTest() : LiveSyncTest(MULTIPLE_CLIENT) {} + virtual ~MultipleClientPasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MultipleClientPasswordsSyncTest); +}; + +// TODO(rsimha): Enable after crbug.com/77993 is fixed. +IN_PROC_BROWSER_TEST_F(MultipleClientPasswordsSyncTest, DISABLED_Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + for (int i = 0; i < num_clients(); ++i) { + PasswordForm form = CreateTestPasswordForm(i); + AddLogin(GetPasswordStore(i), form); + } + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(num_clients(), GetPasswordCount(0)); + ASSERT_TRUE(AllProfilesContainSamePasswordForms()); +} diff --git a/chrome/browser/sync/test/live_sync/multiple_client_preferences_sync_test.cc b/chrome/browser/sync/test/live_sync/multiple_client_preferences_sync_test.cc new file mode 100644 index 0000000..b2b32c6 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/multiple_client_preferences_sync_test.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2011 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 "base/values.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/preferences_helper.h" +#include "chrome/common/pref_names.h" + +using preferences_helper::ChangeListPref; +using preferences_helper::ListPrefMatches; + +class MultipleClientPreferencesSyncTest : public LiveSyncTest { + public: + MultipleClientPreferencesSyncTest() : LiveSyncTest(MULTIPLE_CLIENT) {} + virtual ~MultipleClientPreferencesSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MultipleClientPreferencesSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(MultipleClientPreferencesSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + for (int i = 0; i < num_clients(); ++i) { + ListValue urls; + urls.Append(Value::CreateStringValue( + base::StringPrintf("http://www.google.com/%d", i))); + ChangeListPref(i, prefs::kURLsToRestoreOnStartup, urls); + } + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(ListPrefMatches(prefs::kURLsToRestoreOnStartup)); +} diff --git a/chrome/browser/sync/test/live_sync/multiple_client_sessions_sync_test.cc b/chrome/browser/sync/test/live_sync/multiple_client_sessions_sync_test.cc new file mode 100644 index 0000000..e7236fa --- /dev/null +++ b/chrome/browser/sync/test/live_sync/multiple_client_sessions_sync_test.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2011 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/memory/scoped_vector.h" +#include "base/stringprintf.h" +#include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sessions_helper.h" + +using sessions_helper::CheckForeignSessionsAgainst; +using sessions_helper::CheckInitialState; +using sessions_helper::OpenTabAndGetLocalWindows; + +class MultipleClientSessionsSyncTest : public LiveSyncTest { + public: + MultipleClientSessionsSyncTest() : LiveSyncTest(MULTIPLE_CLIENT) {} + virtual ~MultipleClientSessionsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MultipleClientSessionsSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(MultipleClientSessionsSyncTest, AllChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ScopedVector<SessionWindowVector> client_windows; + + for (int i = 0; i < num_clients(); ++i) { + ASSERT_TRUE(CheckInitialState(i)); + } + + // Open tabs on all clients and retain window information. + for (int i = 0; i < num_clients(); ++i) { + SessionWindowVector* windows = new SessionWindowVector(); + ASSERT_TRUE(OpenTabAndGetLocalWindows( + i, GURL(StringPrintf("about:bubba%i", i)), *windows)); + client_windows.push_back(windows); + } + + // Wait for sync. + ASSERT_TRUE(AwaitQuiescence()); + + // Get foreign session data from all clients and check it against all + // client_windows. + for (int i = 0; i < num_clients(); ++i) { + ASSERT_TRUE(CheckForeignSessionsAgainst(i, client_windows.get())); + } +} + +IN_PROC_BROWSER_TEST_F(MultipleClientSessionsSyncTest, + EncryptedAndChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ScopedVector<SessionWindowVector> client_windows; + + for (int i = 0; i < num_clients(); ++i) { + ASSERT_TRUE(CheckInitialState(i)); + } + + // Enable encryption on client 0, should propagate to all other clients. + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + + // Wait for sync. + // TODO(zea): Fix sync completion detection so we don't need this. For now, + // the profile sync service harness detects completion before all encryption + // changes are propagated. + ASSERT_TRUE(GetClient(0)->AwaitGroupSyncCycleCompletion(clients())); + + // Open tabs on all clients and retain window information. + for (int i = 0; i < num_clients(); ++i) { + SessionWindowVector* windows = new SessionWindowVector(); + ASSERT_TRUE(OpenTabAndGetLocalWindows( + i, GURL(StringPrintf("about:bubba%i", i)), *windows)); + client_windows.push_back(windows); + } + + // Wait for sync. + ASSERT_TRUE(AwaitQuiescence()); + + // Get foreign session data from all clients and check it against all + // client_windows. + for (int i = 0; i < num_clients(); ++i) { + ASSERT_TRUE(IsEncrypted(i, syncable::SESSIONS)); + ASSERT_TRUE(CheckForeignSessionsAgainst(i, client_windows.get())); + } +} diff --git a/chrome/browser/sync/test/live_sync/multiple_client_typed_urls_sync_test.cc b/chrome/browser/sync/test/live_sync/multiple_client_typed_urls_sync_test.cc new file mode 100644 index 0000000..01b0f7c --- /dev/null +++ b/chrome/browser/sync/test/live_sync/multiple_client_typed_urls_sync_test.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 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/i18n/number_formatting.h" +#include "base/memory/scoped_vector.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/typed_urls_helper.h" + +using typed_urls_helper::AddUrlToHistory; +using typed_urls_helper::AssertAllProfilesHaveSameURLsAsVerifier; +using typed_urls_helper::GetTypedUrlsFromClient; + +class MultipleClientTypedUrlsSyncTest : public LiveSyncTest { + public: + MultipleClientTypedUrlsSyncTest() : LiveSyncTest(MULTIPLE_CLIENT) {} + virtual ~MultipleClientTypedUrlsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(MultipleClientTypedUrlsSyncTest); +}; + +// TCM: 3728323 +IN_PROC_BROWSER_TEST_F(MultipleClientTypedUrlsSyncTest, AddToOne) { + const string16 kHistoryUrl( + ASCIIToUTF16("http://www.add-one-history.google.com/")); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Populate one client with a URL, should sync to all others. + GURL new_url(kHistoryUrl); + AddUrlToHistory(0, new_url); + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + ASSERT_EQ(new_url, urls[0].url()); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitGroupSyncCycleCompletion(clients())); + + // All clients should have this URL. + AssertAllProfilesHaveSameURLsAsVerifier(); +} + +IN_PROC_BROWSER_TEST_F(MultipleClientTypedUrlsSyncTest, AddToAll) { + const string16 kHistoryUrl( + ASCIIToUTF16("http://www.add-all-history.google.com/")); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Populate clients with the same URL. + for (int i = 0; i < num_clients(); ++i) { + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(i); + ASSERT_EQ(0U, urls.size()); + + string16 unique_url = kHistoryUrl + base::FormatNumber(i); + GURL new_url(unique_url); + AddUrlToHistory(i, new_url); + + urls = GetTypedUrlsFromClient(i); + ASSERT_EQ(1U, urls.size()); + ASSERT_EQ(new_url, urls[0].url()); + } + + // Wait for sync. + ASSERT_TRUE(AwaitQuiescence()); + + // Verify that all clients have all urls. + AssertAllProfilesHaveSameURLsAsVerifier(); +} + diff --git a/chrome/browser/sync/test/live_sync/passwords_helper.cc b/chrome/browser/sync/test/live_sync/passwords_helper.cc new file mode 100644 index 0000000..b888e25 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/passwords_helper.cc @@ -0,0 +1,205 @@ +// Copyright (c) 2011 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/live_sync/passwords_helper.h" + +#include "base/stringprintf.h" +#include "base/synchronization/waitable_event.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/password_manager/password_form_data.h" +#include "chrome/browser/password_manager/password_store_consumer.h" +#include "chrome/browser/password_manager/password_store.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/browser/browser_thread.h" + +using webkit_glue::PasswordForm; +using sync_datatype_helper::test; + +const std::string kFakeSignonRealm = "http://fake-signon-realm.google.com/"; +const char* kIndexedFakeOrigin = "http://fake-signon-realm.google.com/%d"; + +namespace { + +// We use a WaitableEvent to wait when logins are added, removed, or updated +// instead of running the UI message loop because of a restriction that +// prevents a DB thread from initiating a quit of the UI message loop. +void PasswordStoreCallback(base::WaitableEvent* wait_event) { + // Wake up passwords_helper::AddLogin. + wait_event->Signal(); +} + +class PasswordStoreConsumerHelper : public PasswordStoreConsumer { + public: + explicit PasswordStoreConsumerHelper(std::vector<PasswordForm>* result) + : PasswordStoreConsumer(), + result_(result) {} + + virtual void OnPasswordStoreRequestDone( + CancelableRequestProvider::Handle handle, + const std::vector<PasswordForm*>& result) { + result_->clear(); + for (std::vector<PasswordForm*>::const_iterator it = result.begin(); + it != result.end(); ++it) { + // Make a copy of the form since it gets deallocated after the caller of + // this method returns. + result_->push_back(**it); + } + + // Quit the message loop to wake up passwords_helper::GetLogins. + MessageLoopForUI::current()->Quit(); + } + + private: + std::vector<PasswordForm>* result_; + + DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper); +}; + +} // namespace + +namespace passwords_helper { + +void AddLogin(PasswordStore* store, const PasswordForm& form) { + ASSERT_TRUE(store); + base::WaitableEvent wait_event(true, false); + store->AddLogin(form); + store->ScheduleTask(NewRunnableFunction(&PasswordStoreCallback, &wait_event)); + wait_event.Wait(); +} + +void UpdateLogin(PasswordStore* store, const PasswordForm& form) { + ASSERT_TRUE(store); + base::WaitableEvent wait_event(true, false); + store->UpdateLogin(form); + store->ScheduleTask(NewRunnableFunction(&PasswordStoreCallback, &wait_event)); + wait_event.Wait(); +} + +void GetLogins(PasswordStore* store, std::vector<PasswordForm>& matches) { + ASSERT_TRUE(store); + PasswordForm matcher_form; + matcher_form.signon_realm = kFakeSignonRealm; + PasswordStoreConsumerHelper consumer(&matches); + store->GetLogins(matcher_form, &consumer); + ui_test_utils::RunMessageLoop(); +} + +void RemoveLogin(PasswordStore* store, const PasswordForm& form) { + ASSERT_TRUE(store); + base::WaitableEvent wait_event(true, false); + store->RemoveLogin(form); + store->ScheduleTask(NewRunnableFunction(&PasswordStoreCallback, &wait_event)); + wait_event.Wait(); +} + +void RemoveLogins(PasswordStore* store) { + std::vector<PasswordForm> forms; + GetLogins(store, forms); + for (std::vector<PasswordForm>::iterator it = forms.begin(); + it != forms.end(); ++it) { + RemoveLogin(store, *it); + } +} + +void SetPassphrase(int index, const std::string& passphrase, bool is_creation) { + test()->GetProfile(index)->GetProfileSyncService("")->SetPassphrase( + passphrase, true, is_creation); +} + +PasswordStore* GetPasswordStore(int index) { + return test()->GetProfile(index)->GetPasswordStore(Profile::IMPLICIT_ACCESS); +} + +PasswordStore* GetVerifierPasswordStore() { + return test()->verifier()->GetPasswordStore(Profile::IMPLICIT_ACCESS); +} + +bool ProfileContainsSamePasswordFormsAsVerifier(int index) { + std::vector<PasswordForm> verifier_forms; + std::vector<PasswordForm> forms; + GetLogins(GetVerifierPasswordStore(), verifier_forms); + GetLogins(GetPasswordStore(index), forms); + bool result = ContainsSamePasswordForms(verifier_forms, forms); + if (!result) { + LOG(ERROR) << "Password forms in Verifier Profile:"; + for (std::vector<PasswordForm>::iterator it = verifier_forms.begin(); + it != verifier_forms.end(); ++it) { + LOG(ERROR) << *it << std::endl; + } + LOG(ERROR) << "Password forms in Profile" << index << ":"; + for (std::vector<PasswordForm>::iterator it = forms.begin(); + it != forms.end(); ++it) { + LOG(ERROR) << *it << std::endl; + } + } + return result; +} + +bool ProfilesContainSamePasswordForms(int index_a, int index_b) { + std::vector<PasswordForm> forms_a; + std::vector<PasswordForm> forms_b; + GetLogins(GetPasswordStore(index_a), forms_a); + GetLogins(GetPasswordStore(index_b), forms_b); + bool result = ContainsSamePasswordForms(forms_a, forms_b); + if (!result) { + LOG(ERROR) << "Password forms in Profile" << index_a << ":"; + for (std::vector<PasswordForm>::iterator it = forms_a.begin(); + it != forms_a.end(); ++it) { + LOG(ERROR) << *it << std::endl; + } + LOG(ERROR) << "Password forms in Profile" << index_b << ":"; + for (std::vector<PasswordForm>::iterator it = forms_b.begin(); + it != forms_b.end(); ++it) { + LOG(ERROR) << *it << std::endl; + } + } + return result; +} + +bool AllProfilesContainSamePasswordFormsAsVerifier() { + for (int i = 0; i < test()->num_clients(); ++i) { + if (!ProfileContainsSamePasswordFormsAsVerifier(i)) { + LOG(ERROR) << "Profile " << i << " does not contain the same password " + " forms as the verifier."; + return false; + } + } + return true; +} + +bool AllProfilesContainSamePasswordForms() { + for (int i = 1; i < test()->num_clients(); ++i) { + if (!ProfilesContainSamePasswordForms(0, i)) { + LOG(ERROR) << "Profile " << i << " does not contain the same password " + " forms as Profile 0."; + return false; + } + } + return true; +} + +int GetPasswordCount(int index) { + std::vector<PasswordForm> forms; + GetLogins(GetPasswordStore(index), forms); + return forms.size(); +} + +int GetVerifierPasswordCount() { + std::vector<PasswordForm> verifier_forms; + GetLogins(GetVerifierPasswordStore(), verifier_forms); + return verifier_forms.size(); +} + +PasswordForm CreateTestPasswordForm(int index) { + PasswordForm form; + form.signon_realm = kFakeSignonRealm; + form.origin = GURL(base::StringPrintf(kIndexedFakeOrigin, index)); + form.username_value = ASCIIToUTF16(base::StringPrintf("username%d", index)); + form.password_value = ASCIIToUTF16(base::StringPrintf("password%d", index)); + return form; +} + +} // namespace passwords_helper diff --git a/chrome/browser/sync/test/live_sync/passwords_helper.h b/chrome/browser/sync/test/live_sync/passwords_helper.h new file mode 100644 index 0000000..296d2b9 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/passwords_helper.h @@ -0,0 +1,81 @@ +// Copyright (c) 2011 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_LIVE_SYNC_PASSWORDS_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_PASSWORDS_HELPER_H_ +#pragma once + +#include <vector> + +#include "base/time.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "webkit/glue/password_form.h" + +class PasswordStore; + +namespace passwords_helper { + +// Adds the login held in |form| to the password store |store|. Even though +// logins are normally added asynchronously, this method will block until the +// login is added. +void AddLogin(PasswordStore* store, const webkit_glue::PasswordForm& form); + +// Update the data held in password store |store| with a modified |form|. +// This method blocks until the operation is complete. +void UpdateLogin(PasswordStore* store, const webkit_glue::PasswordForm& form); + +// Searches |store| for all logins matching a fake signon realm used only by +// LivePasswordsSyncTest and adds the results to |matches|. Note that the +// caller is responsible for deleting the forms added to |matches|. +void GetLogins(PasswordStore* store, + std::vector<webkit_glue::PasswordForm>& matches); + +// Removes the login held in |form| from the password store |store|. This +// method blocks until the operation is complete. +void RemoveLogin(PasswordStore* store, const webkit_glue::PasswordForm& form); + +// Removes all password forms from the password store |store|. +void RemoveLogins(PasswordStore* store); + +// Sets the cryptographer's passphrase for the profile at index |index| to +// |passphrase|. |is_creation| is true if a new passphrase is being set up +// and false otherwise. +void SetPassphrase(int index, const std::string& passphrase, bool is_creation); + +// Gets the password store of the profile with index |index|. +PasswordStore* GetPasswordStore(int index); + +// Gets the password store of the verifier profile. +PasswordStore* GetVerifierPasswordStore(); + +// Returns true iff the profile with index |index| contains the same password +// forms as the verifier profile. +bool ProfileContainsSamePasswordFormsAsVerifier(int index); + +// Returns true iff the profile with index |index_a| contains the same +// password forms as the profile with index |index_b|. +bool ProfilesContainSamePasswordForms(int index_a, int index_b); + +// Returns true iff all profiles contain the same password forms as the +// verifier profile. +bool AllProfilesContainSamePasswordFormsAsVerifier(); + +// Returns true iff all profiles contain the same password forms. +bool AllProfilesContainSamePasswordForms(); + +// Returns the number of forms in the password store of the profile with index +// |index|. +int GetPasswordCount(int index); + +// Returns the number of forms in the password store of the verifier profile. +int GetVerifierPasswordCount(); + +// Creates a test password form with a well known fake signon realm used only +// by LivePasswordsSyncTest based on |index|. +webkit_glue::PasswordForm CreateTestPasswordForm(int index); + +} // namespace passwords_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_PASSWORDS_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/performance/autofill_sync_perf_test.cc b/chrome/browser/sync/test/live_sync/performance/autofill_sync_perf_test.cc new file mode 100644 index 0000000..364019d --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/autofill_sync_perf_test.cc @@ -0,0 +1,198 @@ +// Copyright (c) 2011 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 "base/utf_string_conversions.h" +#include "chrome/browser/autofill/autofill_common_test.h" +#include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/autofill_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h" +#include "chrome/browser/webdata/autofill_entry.h" + +using autofill_helper::AllProfilesMatch; +using autofill_helper::GetAllKeys; +using autofill_helper::GetAllProfiles; +using autofill_helper::GetKeyCount; +using autofill_helper::GetProfileCount; +using autofill_helper::RemoveKey; +using autofill_helper::SetProfiles; + +static const int kNumKeys = 150; +static const int kNumProfiles = 150; + +class AutofillSyncPerfTest : public LiveSyncTest { + public: + AutofillSyncPerfTest() + : LiveSyncTest(TWO_CLIENT), + guid_number_(0), + name_number_(0), + value_number_(0) {} + + // Adds |num_profiles| new autofill profiles to the sync profile |profile|. + void AddProfiles(int profile, int num_profiles); + + // Updates all autofill profiles for the sync profile |profile|. + void UpdateProfiles(int profile); + + // Removes all autofill profiles from |profile|. + void RemoveProfiles(int profile); + + // Adds |num_keys| new autofill keys to the sync profile |profile|. + void AddKeys(int profile, int num_keys); + + // Removes all autofill keys from |profile|. + void RemoveKeys(int profile); + + private: + // Returns a new unique autofill profile. + const AutofillProfile NextAutofillProfile(); + + // Returns a new unique autofill key. + const AutofillKey NextAutofillKey(); + + // Returns an unused unique guid. + const std::string NextGUID(); + + // Returns a unique guid based on the input integer |n|. + const std::string IntToGUID(int n); + + // Returns a new unused unique name. + const std::string NextName(); + + // Returns a unique name based on the input integer |n|. + const std::string IntToName(int n); + + // Returns a new unused unique value for autofill entries. + const std::string NextValue(); + + // Returnes a unique value based on the input integer |n|. + const std::string IntToValue(int n); + + int guid_number_; + int name_number_; + int value_number_; + DISALLOW_COPY_AND_ASSIGN(AutofillSyncPerfTest); +}; + +void AutofillSyncPerfTest::AddProfiles(int profile, int num_profiles) { + const std::vector<AutofillProfile*>& all_profiles = + GetAllProfiles(profile); + std::vector<AutofillProfile> autofill_profiles; + for (size_t i = 0; i < all_profiles.size(); ++i) { + autofill_profiles.push_back(*all_profiles[i]); + } + for (int i = 0; i < num_profiles; ++i) { + autofill_profiles.push_back(NextAutofillProfile()); + } + SetProfiles(profile, &autofill_profiles); +} + +void AutofillSyncPerfTest::UpdateProfiles(int profile) { + const std::vector<AutofillProfile*>& all_profiles = + GetAllProfiles(profile); + std::vector<AutofillProfile> autofill_profiles; + for (size_t i = 0; i < all_profiles.size(); ++i) { + autofill_profiles.push_back(*all_profiles[i]); + autofill_profiles.back().SetInfo(AutofillFieldType(NAME_FIRST), + UTF8ToUTF16(NextName())); + } + SetProfiles(profile, &autofill_profiles); +} + +void AutofillSyncPerfTest::RemoveProfiles(int profile) { + std::vector<AutofillProfile> empty; + SetProfiles(profile, &empty); +} + +void AutofillSyncPerfTest::AddKeys(int profile, int num_keys) { + std::set<AutofillKey> keys; + for (int i = 0; i < num_keys; ++i) { + keys.insert(NextAutofillKey()); + } + autofill_helper::AddKeys(profile, keys); +} + +void AutofillSyncPerfTest::RemoveKeys(int profile) { + std::set<AutofillEntry> keys = GetAllKeys(profile); + for (std::set<AutofillEntry>::const_iterator it = keys.begin(); + it != keys.end(); ++it) { + RemoveKey(profile, it->key()); + } +} + +const AutofillProfile AutofillSyncPerfTest::NextAutofillProfile() { + AutofillProfile profile; + autofill_test::SetProfileInfoWithGuid(&profile, NextGUID().c_str(), + NextName().c_str(), "", "", "", "", "", + "", "", "", "", "", "", ""); + return profile; +} + +const AutofillKey AutofillSyncPerfTest::NextAutofillKey() { + return AutofillKey(NextName().c_str(), NextName().c_str()); +} + +const std::string AutofillSyncPerfTest::NextGUID() { + return IntToGUID(guid_number_++); +} + +const std::string AutofillSyncPerfTest::IntToGUID(int n) { + return StringPrintf("00000000-0000-0000-0000-%012X", n); +} + +const std::string AutofillSyncPerfTest::NextName() { + return IntToName(name_number_++); +} + +const std::string AutofillSyncPerfTest::IntToName(int n) { + return StringPrintf("Name%d", n); +} + +const std::string AutofillSyncPerfTest::NextValue() { + return IntToValue(value_number_++); +} + +const std::string AutofillSyncPerfTest::IntToValue(int n) { + return StringPrintf("Value%d", n); +} + +IN_PROC_BROWSER_TEST_F(AutofillSyncPerfTest, AutofillProfiles_P0) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // TCM ID - 7557873. + AddProfiles(0, kNumProfiles); + base::TimeDelta dt = + SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumProfiles, GetProfileCount(1)); + SyncTimingHelper::PrintResult("autofill", "add_autofill_profiles", dt); + + // TCM ID - 7549835. + UpdateProfiles(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumProfiles, GetProfileCount(1)); + SyncTimingHelper::PrintResult("autofill", "update_autofill_profiles", dt); + + // TCM ID - 7553678. + RemoveProfiles(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(0, GetProfileCount(1)); + SyncTimingHelper::PrintResult("autofill", "delete_autofill_profiles", dt); +} + +IN_PROC_BROWSER_TEST_F(AutofillSyncPerfTest, Autofill_P0) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddKeys(0, kNumKeys); + base::TimeDelta dt = + SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumKeys, GetKeyCount(1)); + SyncTimingHelper::PrintResult("autofill", "add_autofill_keys", dt); + + RemoveKeys(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(0, GetKeyCount(1)); + SyncTimingHelper::PrintResult("autofill", "delete_autofill_keys", dt); +} diff --git a/chrome/browser/sync/test/live_sync/performance/bookmarks_sync_perf_test.cc b/chrome/browser/sync/test/live_sync/performance/bookmarks_sync_perf_test.cc new file mode 100644 index 0000000..72103fa --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/bookmarks_sync_perf_test.cc @@ -0,0 +1,107 @@ +// Copyright (c) 2011 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/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/bookmarks_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h" + +using bookmarks_helper::AddURL; +using bookmarks_helper::AllModelsMatch; +using bookmarks_helper::GetBookmarkBarNode; +using bookmarks_helper::IndexedURL; +using bookmarks_helper::IndexedURLTitle; +using bookmarks_helper::Remove; +using bookmarks_helper::SetURL; + +static const int kNumBookmarks = 150; + +class BookmarksSyncPerfTest : public LiveSyncTest { + public: + BookmarksSyncPerfTest() + : LiveSyncTest(TWO_CLIENT), + url_number_(0), + url_title_number_(0) {} + + // Adds |num_urls| new unique bookmarks to the bookmark bar for |profile|. + void AddURLs(int profile, int num_urls); + + // Updates the URL for all bookmarks in the bookmark bar for |profile|. + void UpdateURLs(int profile); + + // Removes all bookmarks in the bookmark bar for |profile|. + void RemoveURLs(int profile); + + // Returns the number of bookmarks stored in the bookmark bar for |profile|. + int GetURLCount(int profile); + + private: + // Returns a new unique bookmark URL. + std::string NextIndexedURL(); + + // Returns a new unique bookmark title. + std::wstring NextIndexedURLTitle(); + + int url_number_; + int url_title_number_; + DISALLOW_COPY_AND_ASSIGN(BookmarksSyncPerfTest); +}; + +void BookmarksSyncPerfTest::AddURLs(int profile, int num_urls) { + for (int i = 0; i < num_urls; ++i) { + ASSERT_TRUE(AddURL( + profile, 0, NextIndexedURLTitle(), GURL(NextIndexedURL())) != NULL); + } +} + +void BookmarksSyncPerfTest::UpdateURLs(int profile) { + for (int i = 0; + i < GetBookmarkBarNode(profile)->child_count(); + ++i) { + ASSERT_TRUE(SetURL(profile, + GetBookmarkBarNode(profile)->GetChild(i), + GURL(NextIndexedURL()))); + } +} + +void BookmarksSyncPerfTest::RemoveURLs(int profile) { + while (!GetBookmarkBarNode(profile)->empty()) { + Remove(profile, GetBookmarkBarNode(profile), 0); + } +} + +int BookmarksSyncPerfTest::GetURLCount(int profile) { + return GetBookmarkBarNode(profile)->child_count(); +} + +std::string BookmarksSyncPerfTest::NextIndexedURL() { + return IndexedURL(url_number_++); +} + +std::wstring BookmarksSyncPerfTest::NextIndexedURLTitle() { + return IndexedURLTitle(url_title_number_++); +} + +IN_PROC_BROWSER_TEST_F(BookmarksSyncPerfTest, P0) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // TCM ID - 7556828. + AddURLs(0, kNumBookmarks); + base::TimeDelta dt = + SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumBookmarks, GetURLCount(1)); + SyncTimingHelper::PrintResult("bookmarks", "add_bookmarks", dt); + + // TCM ID - 7564762. + UpdateURLs(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumBookmarks, GetURLCount(1)); + SyncTimingHelper::PrintResult("bookmarks", "update_bookmarks", dt); + + // TCM ID - 7566626. + RemoveURLs(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(0, GetURLCount(1)); + SyncTimingHelper::PrintResult("bookmarks", "delete_bookmarks", dt); +} diff --git a/chrome/browser/sync/test/live_sync/performance/extensions_sync_perf_test.cc b/chrome/browser/sync/test/live_sync/performance/extensions_sync_perf_test.cc new file mode 100644 index 0000000..dc88286 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/extensions_sync_perf_test.cc @@ -0,0 +1,102 @@ +// Copyright (c) 2011 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/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/extensions_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h" + +using extensions_helper::AllProfilesHaveSameExtensions; +using extensions_helper::AllProfilesHaveSameExtensionsAsVerifier; +using extensions_helper::DisableExtension; +using extensions_helper::EnableExtension; +using extensions_helper::GetInstalledExtensions; +using extensions_helper::InstallExtension; +using extensions_helper::InstallExtensionsPendingForSync; +using extensions_helper::IsExtensionEnabled; +using extensions_helper::UninstallExtension; + +// TODO(braffert): Replicate these tests for apps. + +static const int kNumExtensions = 150; + +class ExtensionsSyncPerfTest : public LiveSyncTest { + public: + ExtensionsSyncPerfTest() + : LiveSyncTest(TWO_CLIENT), + extension_number_(0) {} + + // Adds |num_extensions| new unique extensions to |profile|. + void AddExtensions(int profile, int num_extensions); + + // Updates the enabled/disabled state for all extensions in |profile|. + void UpdateExtensions(int profile); + + // Uninstalls all currently installed extensions from |profile|. + void RemoveExtensions(int profile); + + // Returns the number of currently installed extensions for |profile|. + int GetExtensionCount(int profile); + + private: + int extension_number_; + DISALLOW_COPY_AND_ASSIGN(ExtensionsSyncPerfTest); +}; + +void ExtensionsSyncPerfTest::AddExtensions(int profile, int num_extensions) { + for (int i = 0; i < num_extensions; ++i) { + InstallExtension(GetProfile(profile), extension_number_++); + } +} + +void ExtensionsSyncPerfTest::UpdateExtensions(int profile) { + std::vector<int> extensions = GetInstalledExtensions(GetProfile(profile)); + for (std::vector<int>::iterator it = extensions.begin(); + it != extensions.end(); ++it) { + if (IsExtensionEnabled(GetProfile(profile), *it)) { + DisableExtension(GetProfile(profile), *it); + } else { + EnableExtension(GetProfile(profile), *it); + } + } +} + +int ExtensionsSyncPerfTest::GetExtensionCount(int profile) { + return GetInstalledExtensions(GetProfile(profile)).size(); +} + +void ExtensionsSyncPerfTest::RemoveExtensions(int profile) { + std::vector<int> extensions = GetInstalledExtensions(GetProfile(profile)); + for (std::vector<int>::iterator it = extensions.begin(); + it != extensions.end(); ++it) { + UninstallExtension(GetProfile(profile), *it); + } +} + +IN_PROC_BROWSER_TEST_F(ExtensionsSyncPerfTest, P0) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + int num_default_extensions = GetExtensionCount(0); + int expected_extension_count = num_default_extensions + kNumExtensions; + + // TCM ID - 7563874. + AddExtensions(0, kNumExtensions); + base::TimeDelta dt = + SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + InstallExtensionsPendingForSync(GetProfile(1)); + ASSERT_EQ(expected_extension_count, GetExtensionCount(1)); + SyncTimingHelper::PrintResult("extensions", "add_extensions", dt); + + // TCM ID - 7655397. + UpdateExtensions(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(expected_extension_count, GetExtensionCount(1)); + SyncTimingHelper::PrintResult("extensions", "update_extensions", dt); + + // TCM ID - 7567721. + RemoveExtensions(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(num_default_extensions, GetExtensionCount(1)); + SyncTimingHelper::PrintResult("extensions", "delete_extensions", dt); +} diff --git a/chrome/browser/sync/test/live_sync/performance/passwords_sync_perf_test.cc b/chrome/browser/sync/test/live_sync/performance/passwords_sync_perf_test.cc new file mode 100644 index 0000000..f5dda87 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/passwords_sync_perf_test.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2011 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 "base/utf_string_conversions.h" +#include "chrome/browser/password_manager/password_store.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/passwords_helper.h" +#include "chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h" + +using passwords_helper::AddLogin; +using passwords_helper::CreateTestPasswordForm; +using passwords_helper::GetLogins; +using passwords_helper::GetPasswordCount; +using passwords_helper::GetPasswordStore; +using passwords_helper::UpdateLogin; + +static const int kNumPasswords = 150; + +class PasswordsSyncPerfTest : public LiveSyncTest { + public: + PasswordsSyncPerfTest() : LiveSyncTest(TWO_CLIENT), password_number_(0) {} + + // Adds |num_logins| new unique passwords to |profile|. + void AddLogins(int profile, int num_logins); + + // Updates the password for all logins for |profile|. + void UpdateLogins(int profile); + + // Removes all logins for |profile|. + void RemoveLogins(int profile); + + private: + // Returns a new unique login. + webkit_glue::PasswordForm NextLogin(); + + // Returns a new unique password value. + std::string NextPassword(); + + int password_number_; + DISALLOW_COPY_AND_ASSIGN(PasswordsSyncPerfTest); +}; + +void PasswordsSyncPerfTest::AddLogins(int profile, int num_logins) { + for (int i = 0; i < num_logins; ++i) { + AddLogin(GetPasswordStore(profile), NextLogin()); + } +} + +void PasswordsSyncPerfTest::UpdateLogins(int profile) { + std::vector<webkit_glue::PasswordForm> logins; + GetLogins(GetPasswordStore(profile), logins); + for (std::vector<webkit_glue::PasswordForm>::iterator it = logins.begin(); + it != logins.end(); ++it) { + (*it).password_value = ASCIIToUTF16(NextPassword()); + UpdateLogin(GetPasswordStore(profile), (*it)); + } +} + +void PasswordsSyncPerfTest::RemoveLogins(int profile) { + passwords_helper::RemoveLogins(GetPasswordStore(profile)); +} + +webkit_glue::PasswordForm PasswordsSyncPerfTest::NextLogin() { + return CreateTestPasswordForm(password_number_++); +} + +std::string PasswordsSyncPerfTest::NextPassword() { + return base::StringPrintf("password%d", password_number_++); +} + +IN_PROC_BROWSER_TEST_F(PasswordsSyncPerfTest, P0) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // TCM ID - 7367749. + AddLogins(0, kNumPasswords); + base::TimeDelta dt = + SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumPasswords, GetPasswordCount(1)); + SyncTimingHelper::PrintResult("passwords", "add_passwords", dt); + + // TCM ID - 7365093. + UpdateLogins(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumPasswords, GetPasswordCount(1)); + SyncTimingHelper::PrintResult("passwords", "update_passwords", dt); + + // TCM ID - 7557852 + RemoveLogins(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(0, GetPasswordCount(1)); + SyncTimingHelper::PrintResult("passwords", "delete_passwords", dt); +} diff --git a/chrome/browser/sync/test/live_sync/performance/sessions_sync_perf_test.cc b/chrome/browser/sync/test/live_sync/performance/sessions_sync_perf_test.cc new file mode 100644 index 0000000..90f1a3f --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/sessions_sync_perf_test.cc @@ -0,0 +1,131 @@ +// Copyright (c) 2011 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/ui/browser.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sessions_helper.h" + +using sessions_helper::GetLocalSession; +using sessions_helper::GetSessionData; +using sessions_helper::OpenMultipleTabs; +using sessions_helper::WaitForTabsToLoad; + +static const int kNumTabs = 150; + +class SessionsSyncPerfTest: public LiveSyncTest { + public: + SessionsSyncPerfTest() : LiveSyncTest(TWO_CLIENT), url_number_(0) {} + + // Opens |num_tabs| new tabs on |profile|. + void AddTabs(int profile, int num_tabs); + + // Update all tabs in |profile| by visiting a new URL. + void UpdateTabs(int profile); + + // Close all tabs in |profile|. + void RemoveTabs(int profile); + + // Returns the number of open tabs in all sessions (local + foreign) for + // |profile|. Returns -1 on failure. + int GetTabCount(int profile); + + private: + // Returns a new unique URL. + GURL NextURL(); + + // Returns a unique URL according to the integer |n|. + GURL IntToURL(int n); + + int url_number_; + DISALLOW_COPY_AND_ASSIGN(SessionsSyncPerfTest); +}; + +void SessionsSyncPerfTest::AddTabs(int profile, int num_tabs) { + std::vector<GURL> urls; + for (int i = 0; i < num_tabs; ++i) { + urls.push_back(NextURL()); + } + OpenMultipleTabs(profile, urls); +} + +void SessionsSyncPerfTest::UpdateTabs(int profile) { + Browser* browser = GetBrowser(profile); + GURL url; + std::vector<GURL> urls; + for (int i = 0; i < browser->tab_count(); ++i) { + browser->SelectNumberedTab(i); + url = NextURL(); + browser->OpenURL( + OpenURLParams(url, GURL("www.google.com"), CURRENT_TAB, 0)); + urls.push_back(url); + } + WaitForTabsToLoad(profile, urls); +} + +void SessionsSyncPerfTest::RemoveTabs(int profile) { + GetBrowser(profile)->CloseAllTabs(); +} + +int SessionsSyncPerfTest::GetTabCount(int profile) { + int tab_count = 0; + const SyncedSession* local_session; + SyncedSessionVector sessions; + + if (!GetLocalSession(profile, &local_session)) { + VLOG(1) << "GetLocalSession returned false"; + return -1; + } + + if (!GetSessionData(profile, &sessions)) { + // Foreign session data may be empty. In this case we only count tabs in + // the local session. + VLOG(1) << "GetSessionData returned false"; + } + + sessions.push_back(local_session); + for (SyncedSessionVector::const_iterator it = sessions.begin(); + it != sessions.end(); ++it) { + for (SessionWindowVector::const_iterator win_it = (*it)->windows.begin(); + win_it != (*it)->windows.end(); + ++win_it) { + tab_count += (*win_it)->tabs.size(); + } + } + return tab_count; +} + +GURL SessionsSyncPerfTest::NextURL() { + return IntToURL(url_number_++); +} + +GURL SessionsSyncPerfTest::IntToURL(int n) { + return GURL(StringPrintf("http://history%d.google.com/", n)); +} + +IN_PROC_BROWSER_TEST_F(SessionsSyncPerfTest, P0) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddTabs(0, kNumTabs); + base::TimeDelta dt = + SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumTabs, GetTabCount(0)); + ASSERT_EQ(kNumTabs, GetTabCount(1)); + SyncTimingHelper::PrintResult("tabs", "add_tabs", dt); + + UpdateTabs(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumTabs, GetTabCount(0)); + ASSERT_EQ(kNumTabs, GetTabCount(1)); + SyncTimingHelper::PrintResult("tabs", "update_tabs", dt); + + RemoveTabs(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + // New tab page remains open on profile 0 after closing all tabs. + ASSERT_EQ(1, GetTabCount(0)); + ASSERT_EQ(0, GetTabCount(1)); + SyncTimingHelper::PrintResult("tabs", "delete_tabs", dt); +} diff --git a/chrome/browser/sync/test/live_sync/performance/sync_timing_helper.cc b/chrome/browser/sync/test/live_sync/performance/sync_timing_helper.cc new file mode 100644 index 0000000..8d985f6 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/sync_timing_helper.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011 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/live_sync/performance/sync_timing_helper.h" + +#include "base/string_number_conversions.h" +#include "base/time.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "testing/gtest/include/gtest/gtest.h" + +SyncTimingHelper::SyncTimingHelper() {} + +SyncTimingHelper::~SyncTimingHelper() {} + +// static +base::TimeDelta SyncTimingHelper::TimeSyncCycle( + ProfileSyncServiceHarness* client) { + base::Time start = base::Time::Now(); + EXPECT_TRUE(client->AwaitSyncCycleCompletion("Timing sync cycle.")); + return base::Time::Now() - start; +} + +// static +base::TimeDelta SyncTimingHelper::TimeMutualSyncCycle( + ProfileSyncServiceHarness* client, ProfileSyncServiceHarness* partner) { + base::Time start = base::Time::Now(); + EXPECT_TRUE(client->AwaitMutualSyncCycleCompletion(partner)); + return base::Time::Now() - start; +} + +// static +base::TimeDelta SyncTimingHelper::TimeUntilQuiescence( + std::vector<ProfileSyncServiceHarness*>& clients) { + base::Time start = base::Time::Now(); + EXPECT_TRUE(ProfileSyncServiceHarness::AwaitQuiescence(clients)); + return base::Time::Now() - start; +} + +// static +void SyncTimingHelper::PrintResult(const std::string& measurement, + const std::string& trace, + const base::TimeDelta& dt) { + printf("*RESULT %s: %s= %s ms\n", measurement.c_str(), trace.c_str(), + base::IntToString(dt.InMillisecondsF()).c_str()); +} diff --git a/chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h b/chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h new file mode 100644 index 0000000..8d87aeb --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011 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_LIVE_SYNC_PERFORMANCE_SYNC_TIMING_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_PERFORMANCE_SYNC_TIMING_HELPER_H_ +#pragma once + +#include "base/basictypes.h" + +#include <string> +#include <vector> + +namespace base { +class TimeDelta; +} + +class ProfileSyncServiceHarness; + +class SyncTimingHelper { + public: + SyncTimingHelper(); + ~SyncTimingHelper(); + + // Returns the time taken for |client| to complete a single sync cycle. + static base::TimeDelta TimeSyncCycle(ProfileSyncServiceHarness* client); + + // Returns the time taken for both |client| and |partner| to complete a sync + // cycle. + static base::TimeDelta TimeMutualSyncCycle( + ProfileSyncServiceHarness* client, ProfileSyncServiceHarness* partner); + + // Returns the time taken for all clients in |clients| to complete their + // respective sync cycles. + static base::TimeDelta TimeUntilQuiescence( + std::vector<ProfileSyncServiceHarness*>& clients); + + // Print a timing measurement in a format appropriate for the chromium perf + // dashboard. Simplified version of methods defined in + // chrome/test/ui/ui_perf_test.{h,cc}. + static void PrintResult(const std::string& measurement, + const std::string& trace, + const base::TimeDelta& dt); + + private: + DISALLOW_COPY_AND_ASSIGN(SyncTimingHelper); +}; + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_PERFORMANCE_SYNC_TIMING_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/performance/typed_urls_sync_perf_test.cc b/chrome/browser/sync/test/live_sync/performance/typed_urls_sync_perf_test.cc new file mode 100644 index 0000000..1aa8535 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/performance/typed_urls_sync_perf_test.cc @@ -0,0 +1,102 @@ +// Copyright (c) 2011 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/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/performance/sync_timing_helper.h" +#include "chrome/browser/sync/test/live_sync/typed_urls_helper.h" + +using typed_urls_helper::AddUrlToHistory; +using typed_urls_helper::AssertAllProfilesHaveSameURLsAsVerifier; +using typed_urls_helper::DeleteUrlFromHistory; +using typed_urls_helper::GetTypedUrlsFromClient; + +static const int kNumUrls = 150; + +class TypedUrlsSyncPerfTest : public LiveSyncTest { + public: + TypedUrlsSyncPerfTest() + : LiveSyncTest(TWO_CLIENT), + url_number_(0) {} + + // Adds |num_urls| new unique typed urls to |profile|. + void AddURLs(int profile, int num_urls); + + // Update all typed urls in |profile| by visiting them once again. + void UpdateURLs(int profile); + + // Removes all typed urls for |profile|. + void RemoveURLs(int profile); + + // Returns the number of typed urls stored in |profile|. + int GetURLCount(int profile); + + private: + // Returns a new unique typed URL. + GURL NextURL(); + + // Returns a unique URL according to the integer |n|. + GURL IntToURL(int n); + + int url_number_; + DISALLOW_COPY_AND_ASSIGN(TypedUrlsSyncPerfTest); +}; + +void TypedUrlsSyncPerfTest::AddURLs(int profile, int num_urls) { + for (int i = 0; i < num_urls; ++i) { + AddUrlToHistory(profile, NextURL()); + } +} + +void TypedUrlsSyncPerfTest::UpdateURLs(int profile) { + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(profile); + for (std::vector<history::URLRow>::const_iterator it = urls.begin(); + it != urls.end(); ++it) { + AddUrlToHistory(profile, it->url()); + } +} + +void TypedUrlsSyncPerfTest::RemoveURLs(int profile) { + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(profile); + for (std::vector<history::URLRow>::const_iterator it = urls.begin(); + it != urls.end(); ++it) { + DeleteUrlFromHistory(profile, it->url()); + } +} + +int TypedUrlsSyncPerfTest::GetURLCount(int profile) { + return GetTypedUrlsFromClient(profile).size(); +} + +GURL TypedUrlsSyncPerfTest::NextURL() { + return IntToURL(url_number_++); +} + +GURL TypedUrlsSyncPerfTest::IntToURL(int n) { + return GURL(StringPrintf("http://history%d.google.com/", n)); +} + +IN_PROC_BROWSER_TEST_F(TypedUrlsSyncPerfTest, P0) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // TCM ID - 7985716. + AddURLs(0, kNumUrls); + base::TimeDelta dt = + SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumUrls, GetURLCount(1)); + SyncTimingHelper::PrintResult("typed_urls", "add_typed_urls", dt); + + // TCM ID - 7981755. + UpdateURLs(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(kNumUrls, GetURLCount(1)); + SyncTimingHelper::PrintResult("typed_urls", "update_typed_urls", dt); + + // TCM ID - 7651271. + RemoveURLs(0); + dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1)); + ASSERT_EQ(0, GetURLCount(1)); + SyncTimingHelper::PrintResult("typed_urls", "delete_typed_urls", dt); +} diff --git a/chrome/browser/sync/test/live_sync/preferences_helper.cc b/chrome/browser/sync/test/live_sync/preferences_helper.cc new file mode 100644 index 0000000..89d59d5 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/preferences_helper.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2011 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/live_sync/preferences_helper.h" + +#include "base/values.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/prefs/scoped_user_pref_update.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" + +using sync_datatype_helper::test; + +namespace preferences_helper { + +PrefService* GetPrefs(int index) { + return test()->GetProfile(index)->GetPrefs(); +} + +PrefService* GetVerifierPrefs() { + return test()->verifier()->GetPrefs(); +} + +void ChangeBooleanPref(int index, const char* pref_name) { + bool new_value = !GetPrefs(index)->GetBoolean(pref_name); + GetPrefs(index)->SetBoolean(pref_name, new_value); + if (test()->use_verifier()) + GetVerifierPrefs()->SetBoolean(pref_name, new_value); +} + +void ChangeIntegerPref(int index, const char* pref_name, int new_value) { + GetPrefs(index)->SetInteger(pref_name, new_value); + if (test()->use_verifier()) + GetVerifierPrefs()->SetInteger(pref_name, new_value); +} + +void ChangeDoublePref(int index, const char* pref_name, double new_value) { + GetPrefs(index)->SetDouble(pref_name, new_value); + if (test()->use_verifier()) + GetVerifierPrefs()->SetDouble(pref_name, new_value); +} + +void ChangeStringPref(int index, + const char* pref_name, + const std::string& new_value) { + GetPrefs(index)->SetString(pref_name, new_value); + if (test()->use_verifier()) + GetVerifierPrefs()->SetString(pref_name, new_value); +} + +void AppendStringPref(int index, + const char* pref_name, + const std::string& append_value) { + ChangeStringPref(index, + pref_name, + GetPrefs(index)->GetString(pref_name) + append_value); +} + +void ChangeFilePathPref(int index, + const char* pref_name, + const FilePath& new_value) { + GetPrefs(index)->SetFilePath(pref_name, new_value); + if (test()->use_verifier()) + GetVerifierPrefs()->SetFilePath(pref_name, new_value); +} + +void ChangeListPref(int index, + const char* pref_name, + const ListValue& new_value) { + { + ListPrefUpdate update(GetPrefs(index), pref_name); + ListValue* list = update.Get(); + for (ListValue::const_iterator it = new_value.begin(); + it != new_value.end(); + ++it) { + list->Append((*it)->DeepCopy()); + } + } + + if (test()->use_verifier()) { + ListPrefUpdate update_verifier(GetVerifierPrefs(), pref_name); + ListValue* list_verifier = update_verifier.Get(); + for (ListValue::const_iterator it = new_value.begin(); + it != new_value.end(); + ++it) { + list_verifier->Append((*it)->DeepCopy()); + } + } +} + +bool BooleanPrefMatches(const char* pref_name) { + bool reference_value; + if (test()->use_verifier()) { + reference_value = GetVerifierPrefs()->GetBoolean(pref_name); + } else { + reference_value = GetPrefs(0)->GetBoolean(pref_name); + } + for (int i = 0; i < test()->num_clients(); ++i) { + if (reference_value != GetPrefs(i)->GetBoolean(pref_name)) { + LOG(ERROR) << "Boolean preference " << pref_name << " mismatched in" + << " profile " << i << "."; + return false; + } + } + return true; +} + +bool IntegerPrefMatches(const char* pref_name) { + int reference_value; + if (test()->use_verifier()) { + reference_value = GetVerifierPrefs()->GetInteger(pref_name); + } else { + reference_value = GetPrefs(0)->GetInteger(pref_name); + } + for (int i = 0; i < test()->num_clients(); ++i) { + if (reference_value != GetPrefs(i)->GetInteger(pref_name)) { + LOG(ERROR) << "Integer preference " << pref_name << " mismatched in" + << " profile " << i << "."; + return false; + } + } + return true; +} + +bool DoublePrefMatches(const char* pref_name) { + double reference_value; + if (test()->use_verifier()) { + reference_value = GetVerifierPrefs()->GetDouble(pref_name); + } else { + reference_value = GetPrefs(0)->GetDouble(pref_name); + } + for (int i = 0; i < test()->num_clients(); ++i) { + if (reference_value != GetPrefs(i)->GetDouble(pref_name)) { + LOG(ERROR) << "Double preference " << pref_name << " mismatched in" + << " profile " << i << "."; + return false; + } + } + return true; +} + +bool StringPrefMatches(const char* pref_name) { + std::string reference_value; + if (test()->use_verifier()) { + reference_value = GetVerifierPrefs()->GetString(pref_name); + } else { + reference_value = GetPrefs(0)->GetString(pref_name); + } + for (int i = 0; i < test()->num_clients(); ++i) { + if (reference_value != GetPrefs(i)->GetString(pref_name)) { + LOG(ERROR) << "String preference " << pref_name << " mismatched in" + << " profile " << i << "."; + return false; + } + } + return true; +} + +bool FilePathPrefMatches(const char* pref_name) { + FilePath reference_value; + if (test()->use_verifier()) { + reference_value = GetVerifierPrefs()->GetFilePath(pref_name); + } else { + reference_value = GetPrefs(0)->GetFilePath(pref_name); + } + for (int i = 0; i < test()->num_clients(); ++i) { + if (reference_value != GetPrefs(i)->GetFilePath(pref_name)) { + LOG(ERROR) << "FilePath preference " << pref_name << " mismatched in" + << " profile " << i << "."; + return false; + } + } + return true; +} + +bool ListPrefMatches(const char* pref_name) { + const ListValue* reference_value; + if (test()->use_verifier()) { + reference_value = GetVerifierPrefs()->GetList(pref_name); + } else { + reference_value = GetPrefs(0)->GetList(pref_name); + } + for (int i = 0; i < test()->num_clients(); ++i) { + if (!reference_value->Equals(GetPrefs(i)->GetList(pref_name))) { + LOG(ERROR) << "List preference " << pref_name << " mismatched in" + << " profile " << i << "."; + return false; + } + } + return true; +} + +} // namespace preferences_helper diff --git a/chrome/browser/sync/test/live_sync/preferences_helper.h b/chrome/browser/sync/test/live_sync/preferences_helper.h new file mode 100644 index 0000000..6fa4ce0 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/preferences_helper.h @@ -0,0 +1,100 @@ +// Copyright (c) 2011 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_LIVE_SYNC_PREFERENCES_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_PREFERENCES_HELPER_H_ +#pragma once + +#include "base/file_path.h" +#include "base/values.h" + +#include <string> + +class PrefService; + +namespace preferences_helper { + +// Used to access the preferences within a particular sync profile. +PrefService* GetPrefs(int index); + +// Used to access the preferences within the verifier sync profile. +PrefService* GetVerifierPrefs(); + +// Inverts the value of the boolean preference with name |pref_name| in the +// profile with index |index|. Also inverts its value in |verifier| if +// DisableVerifier() hasn't been called. +void ChangeBooleanPref(int index, const char* pref_name); + +// Changes the value of the integer preference with name |pref_name| in the +// profile with index |index| to |new_value|. Also changes its value in +// |verifier| if DisableVerifier() hasn't been called. +void ChangeIntegerPref(int index, const char* pref_name, int new_value); + +// Changes the value of the double preference with name |pref_name| in the +// profile with index |index| to |new_value|. Also changes its value in +// |verifier| if DisableVerifier() hasn't been called. +void ChangeDoublePref(int index, const char* pref_name, double new_value); + +// Changes the value of the string preference with name |pref_name| in the +// profile with index |index| to |new_value|. Also changes its value in +// |verifier| if DisableVerifier() hasn't been called. +void ChangeStringPref(int index, + const char* pref_name, + const std::string& new_value); + +// Modifies the value of the string preference with name |pref_name| in the +// profile with index |index| by appending |append_value| to its current +// value. Also changes its value in |verifier| if DisableVerifier() hasn't +// been called. +void AppendStringPref(int index, + const char* pref_name, + const std::string& append_value); + +// Changes the value of the file path preference with name |pref_name| in the +// profile with index |index| to |new_value|. Also changes its value in +// |verifier| if DisableVerifier() hasn't been called. +void ChangeFilePathPref(int index, + const char* pref_name, + const FilePath& new_value); + +// Changes the value of the list preference with name |pref_name| in the +// profile with index |index| to |new_value|. Also changes its value in +// |verifier| if DisableVerifier() hasn't been called. +void ChangeListPref(int index, + const char* pref_name, + const ListValue& new_value); + +// Used to verify that the boolean preference with name |pref_name| has the +// same value across all profiles. Also checks |verifier| if DisableVerifier() +// hasn't been called. +bool BooleanPrefMatches(const char* pref_name) WARN_UNUSED_RESULT; + +// Used to verify that the integer preference with name |pref_name| has the +// same value across all profiles. Also checks |verifier| if DisableVerifier() +// hasn't been called. +bool IntegerPrefMatches(const char* pref_name) WARN_UNUSED_RESULT; + +// Used to verify that the double preference with name |pref_name| has the +// same value across all profiles. Also checks |verifier| if DisableVerifier() +// hasn't been called. +bool DoublePrefMatches(const char* pref_name) WARN_UNUSED_RESULT; + +// Used to verify that the string preference with name |pref_name| has the +// same value across all profiles. Also checks |verifier| if DisableVerifier() +// hasn't been called. +bool StringPrefMatches(const char* pref_name) WARN_UNUSED_RESULT; + +// Used to verify that the file path preference with name |pref_name| has the +// same value across all profiles. Also checks |verifier| if DisableVerifier() +// hasn't been called. +bool FilePathPrefMatches(const char* pref_name) WARN_UNUSED_RESULT; + +// Used to verify that the list preference with name |pref_name| has the +// same value across all profiles. Also checks |verifier| if DisableVerifier() +// hasn't been called. +bool ListPrefMatches(const char* pref_name) WARN_UNUSED_RESULT; + +} // namespace preferences_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_PREFERENCES_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/sessions_helper.cc b/chrome/browser/sync/test/live_sync/sessions_helper.cc new file mode 100644 index 0000000..af18366 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sessions_helper.cc @@ -0,0 +1,293 @@ +// Copyright (c) 2011 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/live_sync/sessions_helper.h" + +#include "base/stl_util.h" +#include "base/test/test_timeouts.h" +#include "base/time.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/glue/session_model_associator.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/browser/browser_thread.h" +#include "content/browser/tab_contents/tab_contents.h" +#include "googleurl/src/gurl.h" + +using sync_datatype_helper::test; + +namespace sessions_helper { + +bool GetLocalSession(int index, const SyncedSession** session) { + return test()->GetProfile(index)->GetProfileSyncService()-> + GetSessionModelAssociator()->GetLocalSession(session); +} + +bool ModelAssociatorHasTabWithUrl(int index, const GURL& url) { + ui_test_utils::RunAllPendingInMessageLoop(); + const SyncedSession* local_session; + if (!GetLocalSession(index, &local_session)) { + return false; + } + + if (local_session->windows.size() == 0) { + VLOG(1) << "Empty windows vector"; + return false; + } + + int nav_index; + TabNavigation nav; + for (SessionWindowVector::const_iterator it = + local_session->windows.begin(); it != local_session->windows.end(); + ++it) { + if ((*it)->tabs.size() == 0) { + VLOG(1) << "Empty tabs vector"; + continue; + } + for (std::vector<SessionTab*>::const_iterator tab_it = + (*it)->tabs.begin(); tab_it != (*it)->tabs.end(); ++tab_it) { + if ((*tab_it)->navigations.size() == 0) { + VLOG(1) << "Empty navigations vector"; + continue; + } + nav_index = (*tab_it)->current_navigation_index; + nav = (*tab_it)->navigations[nav_index]; + if (nav.virtual_url() == url) { + VLOG(1) << "Found tab with url " << url.spec(); + if (nav.title().empty()) { + VLOG(1) << "No title!"; + continue; + } + return true; + } + } + } + VLOG(1) << "Could not find tab with url " << url.spec(); + return false; +} + +bool OpenTab(int index, const GURL& url) { + VLOG(1) << "Opening tab: " << url.spec() << " using profile " << index << "."; + test()->GetBrowser(index)->ShowSingletonTab(url); + return WaitForTabsToLoad(index, std::vector<GURL>(1, url)); +} + +bool OpenMultipleTabs(int index, const std::vector<GURL>& urls) { + Browser* browser = test()->GetBrowser(index); + for (std::vector<GURL>::const_iterator it = urls.begin(); + it != urls.end(); ++it) { + VLOG(1) << "Opening tab: " << it->spec() << " using profile " << index + << "."; + browser->ShowSingletonTab(*it); + } + return WaitForTabsToLoad(index, urls); +} + +bool WaitForTabsToLoad(int index, const std::vector<GURL>& urls) { + VLOG(1) << "Waiting for session to propagate to associator."; + static const int timeout_milli = TestTimeouts::action_max_timeout_ms(); + base::TimeTicks start_time = base::TimeTicks::Now(); + base::TimeTicks end_time = start_time + + base::TimeDelta::FromMilliseconds(timeout_milli); + bool found; + for (std::vector<GURL>::const_iterator it = urls.begin(); + it != urls.end(); ++it) { + found = false; + while (!found) { + found = ModelAssociatorHasTabWithUrl(index, *it); + if (base::TimeTicks::Now() >= end_time) { + LOG(ERROR) << "Failed to find all tabs after " << timeout_milli/1000.0 + << " seconds."; + return false; + } + if (!found) { + test()->GetProfile(index)->GetProfileSyncService()-> + GetSessionModelAssociator()-> + BlockUntilLocalChangeForTest(timeout_milli); + ui_test_utils::RunMessageLoop(); + } + } + } + return true; +} + +bool GetLocalWindows(int index, SessionWindowVector& local_windows) { + // The local session provided by GetLocalSession is owned, and has lifetime + // controlled, by the model associator, so we must make our own copy. + const SyncedSession* local_session; + if (!GetLocalSession(index, &local_session)) { + return false; + } + for (size_t w = 0; w < local_session->windows.size(); ++w) { + const SessionWindow& window = *local_session->windows.at(w); + SessionWindow* new_window = new SessionWindow(); + for (size_t t = 0; t < window.tabs.size(); ++t) { + const SessionTab& tab = *window.tabs.at(t); + SessionTab* new_tab = new SessionTab(); + new_tab->navigations.resize(tab.navigations.size()); + std::copy(tab.navigations.begin(), tab.navigations.end(), + new_tab->navigations.begin()); + new_window->tabs.push_back(new_tab); + } + local_windows.push_back(new_window); + } + + // Sort the windows so their order is deterministic. + SortSessionWindows(local_windows); + + return true; +} + +bool OpenTabAndGetLocalWindows(int index, + const GURL& url, + SessionWindowVector& local_windows) { + if (!OpenTab(index, url)) { + return false; + } + return GetLocalWindows(index, local_windows); +} + +bool CheckInitialState(int index) { + if (0 != GetNumWindows(index)) + return false; + if (0 != GetNumForeignSessions(index)) + return false; + return true; +} + +int GetNumWindows(int index) { + const SyncedSession* local_session; + if (!GetLocalSession(index, &local_session)) { + return 0; + } + return local_session->windows.size(); +} + +int GetNumForeignSessions(int index) { + SyncedSessionVector sessions; + if (!test()->GetProfile(index)->GetProfileSyncService()-> + GetSessionModelAssociator()->GetAllForeignSessions(&sessions)) + return 0; + return sessions.size(); +} + +bool GetSessionData(int index, SyncedSessionVector* sessions) { + if (!test()->GetProfile(index)->GetProfileSyncService()-> + GetSessionModelAssociator()->GetAllForeignSessions(sessions)) + return false; + SortSyncedSessions(sessions); + return true; +} + +bool CompareSessionWindows(SessionWindow* lhs, SessionWindow* rhs) { + if (!lhs || + !rhs || + lhs->tabs.size() < 1 || + rhs->tabs.size() < 1 || + lhs->tabs[0]->navigations.size() < 1 || + rhs->tabs[0]->navigations.size() < 1) { + // Catchall for uncomparable data. + return false; + } + + return lhs->tabs[0]->navigations[0].virtual_url() < + rhs->tabs[0]->navigations[0].virtual_url(); +} + +void SortSessionWindows(SessionWindowVector& windows) { + std::sort(windows.begin(), windows.end(), + CompareSessionWindows); +} + +bool CompareSyncedSessions(const SyncedSession* lhs, const SyncedSession* rhs) { + if (!lhs || + !rhs || + lhs->windows.size() < 1 || + rhs->windows.size() < 1) { + // Catchall for uncomparable data. + return false; + } + + return CompareSessionWindows(lhs->windows[0], rhs->windows[0]); +} + +void SortSyncedSessions(SyncedSessionVector* sessions) { + std::sort(sessions->begin(), sessions->end(), + CompareSyncedSessions); +} + +bool NavigationEquals(const TabNavigation& expected, + const TabNavigation& actual) { + if (expected.virtual_url() != actual.virtual_url()) { + LOG(ERROR) << "Expected url " << expected.virtual_url() + << ", actual " << actual.virtual_url(); + return false; + } + if (expected.referrer() != actual.referrer()) { + LOG(ERROR) << "Expected referrer " << expected.referrer() + << ", actual " << actual.referrer(); + return false; + } + if (expected.title() != actual.title()) { + LOG(ERROR) << "Expected title " << expected.title() + << ", actual " << actual.title(); + return false; + } + if (expected.transition() != actual.transition()) { + LOG(ERROR) << "Expected transition " << expected.transition() + << ", actual " << actual.transition(); + return false; + } + return true; +} + +bool WindowsMatch(const SessionWindowVector& win1, + const SessionWindowVector& win2) { + SessionTab* client0_tab; + SessionTab* client1_tab; + if (win1.size() != win2.size()) + return false; + for (size_t i = 0; i < win1.size(); ++i) { + if (win1[i]->tabs.size() != win2[i]->tabs.size()) + return false; + for (size_t j = 0; j < win1[i]->tabs.size(); ++j) { + client0_tab = win1[i]->tabs[j]; + client1_tab = win2[i]->tabs[j]; + for (size_t k = 0; k < client0_tab->navigations.size(); ++k) { + if (!NavigationEquals(client0_tab->navigations[k], + client1_tab->navigations[k])) { + return false; + } + } + } + } + + return true; +} + +bool CheckForeignSessionsAgainst( + int index, + const std::vector<SessionWindowVector*>& windows) { + SyncedSessionVector sessions; + if (!GetSessionData(index, &sessions)) + return false; + if ((size_t)(test()->num_clients()-1) != sessions.size()) + return false; + + int window_index = 0; + for (size_t j = 0; j < sessions.size(); ++j, ++window_index) { + if (window_index == index) + window_index++; // Skip self. + if (!WindowsMatch(sessions[j]->windows, *windows[window_index])) + return false; + } + + return true; +} + +} // namespace sessions_helper diff --git a/chrome/browser/sync/test/live_sync/sessions_helper.h b/chrome/browser/sync/test/live_sync/sessions_helper.h new file mode 100644 index 0000000..f508b4b --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sessions_helper.h @@ -0,0 +1,109 @@ +// Copyright (c) 2011 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_LIVE_SYNC_SESSIONS_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_SESSIONS_HELPER_H_ +#pragma once + +#include <algorithm> +#include <vector> + +#include "base/compiler_specific.h" +#include "chrome/browser/sessions/session_types.h" +#include "chrome/browser/sync/engine/nigori_util.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +class GURL; + +typedef std::vector<const SyncedSession*> SyncedSessionVector; +typedef std::vector<SessionWindow*> SessionWindowVector; + +namespace sessions_helper { + +// Copies the local session windows of profile |index| to |local_windows|. +// Returns true if successful. +bool GetLocalWindows(int index, SessionWindowVector& local_windows); + +// Creates and verifies the creation of a new window for profile |index| with +// one tab displaying |url|. Copies the SessionWindow associated with the new +// window to |local_windows|. Returns true if successful. +bool OpenTabAndGetLocalWindows(int index, + const GURL& url, + SessionWindowVector& local_windows); + +// Checks that window count and foreign session count are 0. +bool CheckInitialState(int index); + +// Returns number of open windows for a profile. +int GetNumWindows(int index); + +// Returns number of foreign sessions for a profile. +int GetNumForeignSessions(int index); + +// Fills the sessions vector with the model associator's foreign session data. +// Caller owns |sessions|, but not SyncedSessions objects within. +bool GetSessionData(int index, SyncedSessionVector* sessions); + +// Compare session windows based on their first tab's url. +// Returns true if the virtual url of the lhs is < the rhs. +bool CompareSessionWindows(SessionWindow* lhs, SessionWindow* rhs); + +// Sort session windows using our custom comparator (first tab url +// comparison). +void SortSessionWindows(SessionWindowVector& windows); + +// Compares a foreign session based on the first session window. +// Returns true based on the comparison of the session windows. +bool CompareSyncedSessions(const SyncedSession* lhs, const SyncedSession* rhs); + +// Sort a SyncedSession vector using our custom SyncedSession comparator. +void SortSyncedSessions(SyncedSessionVector* sessions); + +// Compares two tab navigations base on the parameters we sync. +// (Namely, we don't sync state or type mask) +bool NavigationEquals(const TabNavigation& expected, + const TabNavigation& actual); + +// Verifies that two SessionWindows match. +// Returns: +// - true if all the following match: +// 1. number of SessionWindows, +// 2. number of tabs per SessionWindow, +// 3. number of tab navigations per tab, +// 4. actual tab navigations contents +// - false otherwise. +bool WindowsMatch(const SessionWindowVector& win1, + const SessionWindowVector& win2); + +// Retrieves the foreign sessions for a particular profile and compares them +// with a reference SessionWindow list. +// Returns true if the session windows of the foreign session matches the +// reference. +bool CheckForeignSessionsAgainst( + int index, + const std::vector<SessionWindowVector*>& windows); + +// Open a single tab and block until the session model associator is aware +// of it. Returns true upon success, false otherwise. +bool OpenTab(int index, const GURL& url); + +// Open multiple tabs and block until the session model associator is aware +// of all of them. Returns true on success, false on failure. +bool OpenMultipleTabs(int index, const std::vector<GURL>& urls); + +// Wait for a session change to propagate to the model associator. Will not +// return until each url in |urls| has been found. +bool WaitForTabsToLoad(int index, const std::vector<GURL>& urls); + +// Check if the session model associator's knows that the current open tab +// has this url. +bool ModelAssociatorHasTabWithUrl(int index, const GURL& url); + +// Stores a pointer to the local session for a given profile in |session|. +// Returns true on success, false on failure. +bool GetLocalSession(int index, const SyncedSession** session); + +} // namespace sessions_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_SESSIONS_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/single_client_apps_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_apps_sync_test.cc new file mode 100644 index 0000000..25b024a --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_apps_sync_test.cc @@ -0,0 +1,56 @@ +// Copyright (c) 2011 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/basictypes.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/apps_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using apps_helper::AllProfilesHaveSameAppsAsVerifier; +using apps_helper::InstallApp; + +class SingleClientAppsSyncTest : public LiveSyncTest { + public: + SingleClientAppsSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + + virtual ~SingleClientAppsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientAppsSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, StartWithNoApps) { + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, StartWithSomeApps) { + ASSERT_TRUE(SetupClients()); + + const int kNumApps = 5; + for (int i = 0; i < kNumApps; ++i) { + InstallApp(GetProfile(0), i); + InstallApp(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomeApps) { + ASSERT_TRUE(SetupSync()); + + const int kNumApps = 5; + for (int i = 0; i < kNumApps; ++i) { + InstallApp(GetProfile(0), i); + InstallApp(verifier(), i); + } + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for app changes.")); + + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} diff --git a/chrome/browser/sync/test/live_sync/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_bookmarks_sync_test.cc new file mode 100644 index 0000000..c4bb875 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_bookmarks_sync_test.cc @@ -0,0 +1,150 @@ +// Copyright (c) 2011 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/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/bookmarks_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using bookmarks_helper::AddFolder; +using bookmarks_helper::AddURL; +using bookmarks_helper::GetBookmarkBarNode; +using bookmarks_helper::GetOtherNode; +using bookmarks_helper::ModelMatchesVerifier; +using bookmarks_helper::Move; +using bookmarks_helper::Remove; +using bookmarks_helper::SetTitle; + +class SingleClientBookmarksSyncTest : public LiveSyncTest { + public: + SingleClientBookmarksSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientBookmarksSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientBookmarksSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, OfflineToOnline) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + DisableNetwork(GetProfile(0)); + const BookmarkNode* node = AddFolder(0, L"title"); + SetTitle(0, node, L"new_title"); + ASSERT_FALSE(GetClient(0)->AwaitSyncCycleCompletion("Offline state change.")); + ASSERT_EQ(ProfileSyncService::Status::OFFLINE_UNSYNCED, + GetClient(0)->GetStatus().summary); + + EnableNetwork(GetProfile(0)); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Commit changes.")); + ASSERT_EQ(ProfileSyncService::Status::READY, + GetClient(0)->GetStatus().summary); + ASSERT_TRUE(ModelMatchesVerifier(0)); +} + +IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, Sanity) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + // Starting state: + // other_node + // -> top + // -> tier1_a + // -> http://mail.google.com "tier1_a_url0" + // -> http://www.pandora.com "tier1_a_url1" + // -> http://www.facebook.com "tier1_a_url2" + // -> tier1_b + // -> http://www.nhl.com "tier1_b_url0" + const BookmarkNode* top = AddFolder(0, GetOtherNode(0), 0, L"top"); + const BookmarkNode* tier1_a = AddFolder(0, top, 0, L"tier1_a"); + const BookmarkNode* tier1_b = AddFolder(0, top, 1, L"tier1_b"); + const BookmarkNode* tier1_a_url0 = AddURL( + 0, tier1_a, 0, L"tier1_a_url0", GURL("http://mail.google.com")); + const BookmarkNode* tier1_a_url1 = AddURL( + 0, tier1_a, 1, L"tier1_a_url1", GURL("http://www.pandora.com")); + const BookmarkNode* tier1_a_url2 = AddURL( + 0, tier1_a, 2, L"tier1_a_url2", GURL("http://www.facebook.com")); + const BookmarkNode* tier1_b_url0 = AddURL( + 0, tier1_b, 0, L"tier1_b_url0", GURL("http://www.nhl.com")); + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for initial sync completed.")); + ASSERT_TRUE(ModelMatchesVerifier(0)); + + // Ultimately we want to end up with the following model; but this test is + // more about the journey than the destination. + // + // bookmark_bar + // -> CNN (www.cnn.com) + // -> tier1_a + // -> tier1_a_url2 (www.facebook.com) + // -> tier1_a_url1 (www.pandora.com) + // -> Porsche (www.porsche.com) + // -> Bank of America (www.bankofamerica.com) + // -> Seattle Bubble + // other_node + // -> top + // -> tier1_b + // -> Wired News (www.wired.com) + // -> tier2_b + // -> tier1_b_url0 + // -> tier3_b + // -> Toronto Maple Leafs (mapleleafs.nhl.com) + // -> Wynn (www.wynnlasvegas.com) + // -> tier1_a_url0 + const BookmarkNode* bar = GetBookmarkBarNode(0); + const BookmarkNode* cnn = AddURL(0, bar, 0, L"CNN", + GURL("http://www.cnn.com")); + ASSERT_TRUE(cnn != NULL); + Move(0, tier1_a, bar, 1); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Bookmark moved.")); + ASSERT_TRUE(ModelMatchesVerifier(0)); + + const BookmarkNode* porsche = AddURL(0, bar, 2, L"Porsche", + GURL("http://www.porsche.com")); + // Rearrange stuff in tier1_a. + ASSERT_EQ(tier1_a, tier1_a_url2->parent()); + ASSERT_EQ(tier1_a, tier1_a_url1->parent()); + Move(0, tier1_a_url2, tier1_a, 0); + Move(0, tier1_a_url1, tier1_a, 2); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Rearrange stuff in tier1_a")); + ASSERT_TRUE(ModelMatchesVerifier(0)); + + ASSERT_EQ(1, tier1_a_url0->parent()->GetIndexOf(tier1_a_url0)); + Move(0, tier1_a_url0, bar, bar->child_count()); + const BookmarkNode* boa = AddURL(0, bar, bar->child_count(), + L"Bank of America", GURL("https://www.bankofamerica.com")); + ASSERT_TRUE(boa != NULL); + Move(0, tier1_a_url0, top, top->child_count()); + const BookmarkNode* bubble = AddURL( + 0, bar, bar->child_count(), L"Seattle Bubble", + GURL("http://seattlebubble.com")); + ASSERT_TRUE(bubble != NULL); + const BookmarkNode* wired = AddURL(0, bar, 2, L"Wired News", + GURL("http://www.wired.com")); + const BookmarkNode* tier2_b = AddFolder( + 0, tier1_b, 0, L"tier2_b"); + Move(0, tier1_b_url0, tier2_b, 0); + Move(0, porsche, bar, 0); + SetTitle(0, wired, L"News Wired"); + SetTitle(0, porsche, L"ICanHazPorsche?"); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Change title.")); + ASSERT_TRUE(ModelMatchesVerifier(0)); + + ASSERT_EQ(tier1_a_url0->id(), top->GetChild(top->child_count() - 1)->id()); + Remove(0, top, top->child_count() - 1); + Move(0, wired, tier1_b, 0); + Move(0, porsche, bar, 3); + const BookmarkNode* tier3_b = AddFolder(0, tier2_b, 1, L"tier3_b"); + const BookmarkNode* leafs = AddURL( + 0, tier1_a, 0, L"Toronto Maple Leafs", GURL("http://mapleleafs.nhl.com")); + const BookmarkNode* wynn = AddURL(0, bar, 1, L"Wynn", + GURL("http://www.wynnlasvegas.com")); + + Move(0, wynn, tier3_b, 0); + Move(0, leafs, tier3_b, 0); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Move after addition of bookmarks.")); + ASSERT_TRUE(ModelMatchesVerifier(0)); +} diff --git a/chrome/browser/sync/test/live_sync/single_client_extensions_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_extensions_sync_test.cc new file mode 100644 index 0000000..7155826 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_extensions_sync_test.cc @@ -0,0 +1,57 @@ +// Copyright (c) 2011 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/basictypes.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/extensions_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using extensions_helper::AllProfilesHaveSameExtensionsAsVerifier; +using extensions_helper::InstallExtension; + +class SingleClientExtensionsSyncTest : public LiveSyncTest { + public: + SingleClientExtensionsSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + + virtual ~SingleClientExtensionsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientExtensionsSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(SingleClientExtensionsSyncTest, StartWithNoExtensions) { + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(SingleClientExtensionsSyncTest, + StartWithSomeExtensions) { + ASSERT_TRUE(SetupClients()); + + const int kNumExtensions = 5; + for (int i = 0; i < kNumExtensions; ++i) { + InstallExtension(GetProfile(0), i); + InstallExtension(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(SingleClientExtensionsSyncTest, InstallSomeExtensions) { + ASSERT_TRUE(SetupSync()); + + const int kNumExtensions = 5; + for (int i = 0; i < kNumExtensions; ++i) { + InstallExtension(GetProfile(0), i); + InstallExtension(verifier(), i); + } + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for extension changes.")); + + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} diff --git a/chrome/browser/sync/test/live_sync/single_client_passwords_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_passwords_sync_test.cc new file mode 100644 index 0000000..3d81f50 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_passwords_sync_test.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011 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/password_manager/password_form_data.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/passwords_helper.h" + +using passwords_helper::AddLogin; +using passwords_helper::CreateTestPasswordForm; +using passwords_helper::GetPasswordCount; +using passwords_helper::GetPasswordStore; +using passwords_helper::GetVerifierPasswordCount; +using passwords_helper::GetVerifierPasswordStore; +using passwords_helper::ProfileContainsSamePasswordFormsAsVerifier; + +using webkit_glue::PasswordForm; + +class SingleClientPasswordsSyncTest : public LiveSyncTest { + public: + SingleClientPasswordsSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientPasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientPasswordsSyncTest); +}; + +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(SingleClientPasswordsSyncTest, DISABLED_Sanity) { +#else +IN_PROC_BROWSER_TEST_F(SingleClientPasswordsSyncTest, Sanity) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + PasswordForm form = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form); + ASSERT_EQ(1, GetVerifierPasswordCount()); + AddLogin(GetPasswordStore(0), form); + ASSERT_EQ(1, GetPasswordCount(0)); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Added a login.")); + ASSERT_TRUE(ProfileContainsSamePasswordFormsAsVerifier(0)); + ASSERT_EQ(1, GetPasswordCount(0)); +} diff --git a/chrome/browser/sync/test/live_sync/single_client_preferences_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_preferences_sync_test.cc new file mode 100644 index 0000000..cb96004 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_preferences_sync_test.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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/common/pref_names.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/preferences_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using preferences_helper::BooleanPrefMatches; +using preferences_helper::ChangeBooleanPref; + +class SingleClientPreferencesSyncTest : public LiveSyncTest { + public: + SingleClientPreferencesSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientPreferencesSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientPreferencesSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(SingleClientPreferencesSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kHomePageIsNewTabPage)); + ChangeBooleanPref(0, prefs::kHomePageIsNewTabPage); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for prefs change.")); + ASSERT_TRUE(BooleanPrefMatches(prefs::kHomePageIsNewTabPage)); +} diff --git a/chrome/browser/sync/test/live_sync/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_sessions_sync_test.cc new file mode 100644 index 0000000..382c983 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_sessions_sync_test.cc @@ -0,0 +1,48 @@ +// Copyright (c) 2011 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/memory/scoped_vector.h" +#include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sessions_helper.h" + +using sessions_helper::CheckInitialState; +using sessions_helper::GetLocalWindows; +using sessions_helper::GetSessionData; +using sessions_helper::OpenTabAndGetLocalWindows; +using sessions_helper::WindowsMatch; + +class SingleClientSessionsSyncTest : public LiveSyncTest { + public: + SingleClientSessionsSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientSessionsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientSessionsSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + + ScopedVector<SessionWindow> old_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(0, + GURL("about:bubba"), + old_windows.get())); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for session change.")); + + // Get foreign session data from client 0. + SyncedSessionVector sessions; + ASSERT_FALSE(GetSessionData(0, &sessions)); + ASSERT_EQ(0U, sessions.size()); + + // Verify client didn't change. + ScopedVector<SessionWindow> new_windows; + ASSERT_TRUE(GetLocalWindows(0, new_windows.get())); + ASSERT_TRUE(WindowsMatch(old_windows.get(), new_windows.get())); +} diff --git a/chrome/browser/sync/test/live_sync/single_client_themes_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_themes_sync_test.cc new file mode 100644 index 0000000..ce5f431 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_themes_sync_test.cc @@ -0,0 +1,99 @@ +// Copyright (c) 2011 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/basictypes.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/themes_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using themes_helper::GetCustomTheme; +using themes_helper::GetThemeID; +using themes_helper::UseCustomTheme; +using themes_helper::UseDefaultTheme; +using themes_helper::UseNativeTheme; +using themes_helper::UsingCustomTheme; +using themes_helper::UsingDefaultTheme; +using themes_helper::UsingNativeTheme; + +class SingleClientThemesSyncTest : public LiveSyncTest { + public: + SingleClientThemesSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientThemesSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientThemesSyncTest); +}; + +// TODO(akalin): Add tests for model association (i.e., tests that +// start with SetupClients(), change the theme state, then call +// SetupSync()). + +IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, CustomTheme) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(verifier())); + + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for custom themes change.")); + + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); +} + +// TODO(sync): Fails on Chrome OS. See http://crbug.com/84575. +#if defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, FAILS_NativeTheme) { +#else +IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, NativeTheme) { +#endif // OS_CHROMEOS + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_FALSE(UsingNativeTheme(GetProfile(0))); + ASSERT_FALSE(UsingNativeTheme(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for custom themes change.")); + + UseNativeTheme(GetProfile(0)); + UseNativeTheme(verifier()); + ASSERT_TRUE(UsingNativeTheme(GetProfile(0))); + ASSERT_TRUE(UsingNativeTheme(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for native themes change.")); + + ASSERT_TRUE(UsingNativeTheme(GetProfile(0))); + ASSERT_TRUE(UsingNativeTheme(verifier())); +} + +IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, DefaultTheme) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_FALSE(UsingDefaultTheme(GetProfile(0))); + ASSERT_FALSE(UsingDefaultTheme(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for custom themes change.")); + + UseDefaultTheme(GetProfile(0)); + UseDefaultTheme(verifier()); + ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for native themes change.")); + + ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(verifier())); +} diff --git a/chrome/browser/sync/test/live_sync/single_client_typed_urls_sync_test.cc b/chrome/browser/sync/test/live_sync/single_client_typed_urls_sync_test.cc new file mode 100644 index 0000000..064d02d --- /dev/null +++ b/chrome/browser/sync/test/live_sync/single_client_typed_urls_sync_test.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011 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/memory/scoped_vector.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/typed_urls_helper.h" + +using typed_urls_helper::AddUrlToHistory; +using typed_urls_helper::AssertAllProfilesHaveSameURLsAsVerifier; +using typed_urls_helper::GetTypedUrlsFromClient; + +const std::string kSanityHistoryUrl = "http://www.sanity-history.google.com"; + +class SingleClientTypedUrlsSyncTest : public LiveSyncTest { + public: + SingleClientTypedUrlsSyncTest() : LiveSyncTest(SINGLE_CLIENT) {} + virtual ~SingleClientTypedUrlsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SingleClientTypedUrlsSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(SingleClientTypedUrlsSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(0U, urls.size()); + + GURL new_url(kSanityHistoryUrl); + AddUrlToHistory(0, new_url); + + urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + ASSERT_EQ(new_url, urls[0].url()); + AssertAllProfilesHaveSameURLsAsVerifier(); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion( + "Waiting for typed url change.")); + + // Verify client did not change. + AssertAllProfilesHaveSameURLsAsVerifier(); +} + diff --git a/chrome/browser/sync/test/live_sync/sync_datatype_helper.cc b/chrome/browser/sync/test/live_sync/sync_datatype_helper.cc new file mode 100644 index 0000000..3e50ced --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sync_datatype_helper.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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/live_sync/sync_datatype_helper.h" + +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +namespace { + +// The LiveSyncTest instance associated with sync_datatype_helper. +static LiveSyncTest* test = NULL; + +} // namespace + +namespace sync_datatype_helper { + +void AssociateWithTest(LiveSyncTest* test) { + ASSERT_TRUE(test != NULL) << "Cannot associate with null test."; + ASSERT_TRUE(::test == NULL) << "Already associated with a test."; + ::test = test; +} + +LiveSyncTest* test() { + EXPECT_TRUE(::test != NULL) << "Must call AssociateWithTest first."; + return ::test; +} + +} // namespace sync_datatype_helper diff --git a/chrome/browser/sync/test/live_sync/sync_datatype_helper.h b/chrome/browser/sync/test/live_sync/sync_datatype_helper.h new file mode 100644 index 0000000..8a2593c --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sync_datatype_helper.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 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_LIVE_SYNC_SYNC_DATATYPE_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_SYNC_DATATYPE_HELPER_H_ +#pragma once + +#include "base/basictypes.h" + +class LiveSyncTest; + +namespace sync_datatype_helper { + +// Associates an instance of LiveSyncTest with sync_datatype_helper. Must be +// called before any of the methods in the per-datatype helper namespaces can be +// used. +void AssociateWithTest(LiveSyncTest* test); + +// Returns a pointer to the instance of LiveSyncTest associated with the +// per-datatype helpers after making sure it is valid. +LiveSyncTest* test(); + +} // namespace sync_datatype_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_SYNC_DATATYPE_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/sync_errors_test.cc b/chrome/browser/sync/test/live_sync/sync_errors_test.cc new file mode 100644 index 0000000..835ece7 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sync_errors_test.cc @@ -0,0 +1,48 @@ +// Copyright (c) 2011 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/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/bookmarks_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using bookmarks_helper::AddFolder; +using bookmarks_helper::SetTitle; + +class SyncErrorTest : public LiveSyncTest{ + public: + SyncErrorTest() : LiveSyncTest(SINGLE_CLIENT) {} + virtual ~SyncErrorTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(SyncErrorTest); +}; + +IN_PROC_BROWSER_TEST_F(SyncErrorTest, BirthdayErrorTest) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + const BookmarkNode* node1 = AddFolder(0, 0, L"title1"); + SetTitle(0, node1, L"new_title1"); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Offline state change.")); + TriggerBirthdayError(); + + // Now make one more change so we will do another sync. + const BookmarkNode* node2 = AddFolder(0, 0, L"title2"); + SetTitle(0, node2, L"new_title2"); + ASSERT_TRUE(GetClient(0)->AwaitSyncDisabled("Birthday error.")); +} + +IN_PROC_BROWSER_TEST_F(SyncErrorTest, TransientErrorTest) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + const BookmarkNode* node1 = AddFolder(0, 0, L"title1"); + SetTitle(0, node1, L"new_title1"); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Offline state change.")); + TriggerTransientError(); + + // Now make one more change so we will do another sync. + const BookmarkNode* node2 = AddFolder(0, 0, L"title2"); + SetTitle(0, node2, L"new_title2"); + ASSERT_TRUE( + GetClient(0)->AwaitExponentialBackoffVerification()); +} diff --git a/chrome/browser/sync/test/live_sync/sync_extension_helper.cc b/chrome/browser/sync/test/live_sync/sync_extension_helper.cc new file mode 100644 index 0000000..e5de2e4 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sync_extension_helper.cc @@ -0,0 +1,361 @@ +// Copyright (c) 2011 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/live_sync/sync_extension_helper.h" + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_service.h" +#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_constants.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +SyncExtensionHelper::ExtensionState::ExtensionState() + : enabled_state(ENABLED), incognito_enabled(false) {} + +SyncExtensionHelper::ExtensionState::~ExtensionState() {} + +bool SyncExtensionHelper::ExtensionState::Equals( + const SyncExtensionHelper::ExtensionState &other) const { + return ((enabled_state == other.enabled_state) && + (incognito_enabled == other.incognito_enabled)); +} + +// static +SyncExtensionHelper* SyncExtensionHelper::GetInstance() { + SyncExtensionHelper* instance = Singleton<SyncExtensionHelper>::get(); + instance->SetupIfNecessary(sync_datatype_helper::test()); + return instance; +} + +SyncExtensionHelper::SyncExtensionHelper() : setup_completed_(false) {} + +SyncExtensionHelper::~SyncExtensionHelper() {} + +// static +std::string SyncExtensionHelper::NameToId(const std::string& name) { + std::string id; + EXPECT_TRUE(Extension::GenerateId(name, &id)); + return id; +} + +void SyncExtensionHelper::SetupIfNecessary(LiveSyncTest* test) { + if (setup_completed_) + return; + + for (int i = 0; i < test->num_clients(); ++i) { + SetupProfile(test->GetProfile(i)); + } + SetupProfile(test->verifier()); + + setup_completed_ = true; +} + +void 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 << ")"; + profile->GetExtensionService()->OnExtensionInstalled( + extension, extension->UpdatesFromGallery(), 0); +} + +void SyncExtensionHelper::UninstallExtension( + Profile* profile, const std::string& name) { + ExtensionService::UninstallExtensionHelper(profile->GetExtensionService(), + NameToId(name)); +} + +std::vector<std::string> SyncExtensionHelper::GetInstalledExtensionNames( + Profile* profile) const { + std::vector<std::string> names; + ExtensionService* extension_service = profile->GetExtensionService(); + + const ExtensionList* extensions = extension_service->extensions(); + for (ExtensionList::const_iterator it = extensions->begin(); + it != extensions->end(); ++it) { + names.push_back((*it)->name()); + } + + const ExtensionList* disabled_extensions = + extension_service->disabled_extensions(); + for (ExtensionList::const_iterator it = disabled_extensions->begin(); + it != disabled_extensions->end(); ++it) { + names.push_back((*it)->name()); + } + + const ExtensionList* terminated_extensions = + extension_service->terminated_extensions(); + for (ExtensionList::const_iterator it = terminated_extensions->begin(); + it != terminated_extensions->end(); ++it) { + names.push_back((*it)->name()); + } + + return names; +} + +void SyncExtensionHelper::EnableExtension(Profile* profile, + const std::string& name) { + profile->GetExtensionService()->EnableExtension(NameToId(name)); +} + +void SyncExtensionHelper::DisableExtension(Profile* profile, + const std::string& name) { + profile->GetExtensionService()->DisableExtension(NameToId(name)); +} + +bool SyncExtensionHelper::IsExtensionEnabled( + Profile* profile, const std::string& name) const { + return profile->GetExtensionService()->IsExtensionEnabled(NameToId(name)); +} + +void SyncExtensionHelper::IncognitoEnableExtension( + Profile* profile, const std::string& name) { + profile->GetExtensionService()->SetIsIncognitoEnabled(NameToId(name), true); +} + +void SyncExtensionHelper::IncognitoDisableExtension( + Profile* profile, const std::string& name) { + profile->GetExtensionService()->SetIsIncognitoEnabled(NameToId(name), false); +} + +bool SyncExtensionHelper::IsIncognitoEnabled( + Profile* profile, const std::string& name) const { + return profile->GetExtensionService()->IsIncognitoEnabled(NameToId(name)); +} + + +bool SyncExtensionHelper::IsExtensionPendingInstallForSync( + Profile* profile, const std::string& id) const { + const PendingExtensionManager* pending_extension_manager = + profile->GetExtensionService()->pending_extension_manager(); + PendingExtensionInfo info; + if (!pending_extension_manager->GetById(id, &info)) { + return false; + } + return info.is_from_sync(); +} + +void SyncExtensionHelper::InstallExtensionsPendingForSync( + Profile* profile, Extension::Type type) { + // TODO(akalin): Mock out the servers that the extensions auto-update + // mechanism talk to so as to more closely match what actually happens. + // Background networking will need to be re-enabled for extensions tests. + + // We make a copy here since InstallExtension() removes the + // extension from the extensions service's copy. + const PendingExtensionManager* pending_extension_manager = + profile->GetExtensionService()->pending_extension_manager(); + PendingExtensionManager::PendingExtensionMap pending_extensions( + pending_extension_manager->begin(), + pending_extension_manager->end()); + for (PendingExtensionManager::const_iterator it = pending_extensions.begin(); + it != pending_extensions.end(); ++it) { + if (!it->second.is_from_sync()) { + continue; + } + const std::string& id = it->first; + StringMap::const_iterator it2 = id_to_name_.find(id); + if (it2 == id_to_name_.end()) { + ADD_FAILURE() << "Could not get name for id " << id + << " (profile = " << profile->GetDebugName() << ")"; + continue; + } + InstallExtension(profile, it2->second, type); + } +} + +SyncExtensionHelper::ExtensionStateMap + SyncExtensionHelper::GetExtensionStates(Profile* profile) { + const std::string& profile_debug_name = profile->GetDebugName(); + + ExtensionStateMap extension_state_map; + + ExtensionService* extension_service = profile->GetExtensionService(); + + const ExtensionList* extensions = extension_service->extensions(); + for (ExtensionList::const_iterator it = extensions->begin(); + it != extensions->end(); ++it) { + const std::string& id = (*it)->id(); + extension_state_map[id].enabled_state = ExtensionState::ENABLED; + extension_state_map[id].incognito_enabled = + extension_service->IsIncognitoEnabled(id); + VLOG(2) << "Extension " << (*it)->id() << " in profile " + << profile_debug_name << " is enabled"; + } + + const ExtensionList* disabled_extensions = + extension_service->disabled_extensions(); + for (ExtensionList::const_iterator it = disabled_extensions->begin(); + it != disabled_extensions->end(); ++it) { + const std::string& id = (*it)->id(); + extension_state_map[id].enabled_state = ExtensionState::DISABLED; + extension_state_map[id].incognito_enabled = + extension_service->IsIncognitoEnabled(id); + VLOG(2) << "Extension " << (*it)->id() << " in profile " + << profile_debug_name << " is disabled"; + } + + const PendingExtensionManager* pending_extension_manager = + extension_service->pending_extension_manager(); + PendingExtensionManager::const_iterator it; + for (it = pending_extension_manager->begin(); + it != pending_extension_manager->end(); ++it) { + const std::string& id = it->first; + extension_state_map[id].enabled_state = ExtensionState::PENDING; + extension_state_map[id].incognito_enabled = + extension_service->IsIncognitoEnabled(id); + VLOG(2) << "Extension " << it->first << " in profile " + << profile_debug_name << " is pending"; + } + + return extension_state_map; +} + +bool SyncExtensionHelper::ExtensionStatesMatch( + Profile* profile1, Profile* profile2) { + const ExtensionStateMap& state_map1 = GetExtensionStates(profile1); + const ExtensionStateMap& state_map2 = GetExtensionStates(profile2); + if (state_map1.size() != state_map2.size()) { + VLOG(1) << "Number of extensions for profile " << profile1->GetDebugName() + << " does not match profile " << profile2->GetDebugName(); + return false; + } + + ExtensionStateMap::const_iterator it1 = state_map1.begin(); + ExtensionStateMap::const_iterator it2 = state_map2.begin(); + while (it1 != state_map1.end()) { + if (it1->first != it2->first) { + VLOG(1) << "Extensions for profile " << profile1->GetDebugName() + << " do not match profile " << profile2->GetDebugName(); + return false; + } else if (!it1->second.Equals(it2->second)) { + VLOG(1) << "Extension states for profile " << profile1->GetDebugName() + << " do not match profile " << profile2->GetDebugName(); + return false; + } + ++it1; + ++it2; + } + return true; +} + +void SyncExtensionHelper::SetupProfile(Profile* profile) { + profile->InitExtensions(true); + profile_extensions_.insert(make_pair(profile, ExtensionNameMap())); +} + +namespace { + +std::string NameToPublicKey(const std::string& name) { + std::string public_key; + std::string pem; + EXPECT_TRUE(Extension::ProducePEM(name, &pem) && + Extension::FormatPEMForFileOutput(pem, &public_key, + true /* is_public */)); + return public_key; +} + +// TODO(akalin): Somehow unify this with MakeExtension() in +// extension_util_unittest.cc. +scoped_refptr<Extension> CreateExtension( + const FilePath& base_dir, const std::string& name, + Extension::Type type) { + DictionaryValue source; + source.SetString(extension_manifest_keys::kName, name); + const std::string& public_key = NameToPublicKey(name); + source.SetString(extension_manifest_keys::kPublicKey, public_key); + source.SetString(extension_manifest_keys::kVersion, "0.0.0.0"); + switch (type) { + case Extension::TYPE_EXTENSION: + // Do nothing. + break; + case Extension::TYPE_THEME: + source.Set(extension_manifest_keys::kTheme, new DictionaryValue()); + break; + case Extension::TYPE_HOSTED_APP: + case Extension::TYPE_PACKAGED_APP: + source.Set(extension_manifest_keys::kApp, new DictionaryValue()); + source.SetString(extension_manifest_keys::kLaunchWebURL, + "http://www.example.com"); + break; + default: + ADD_FAILURE(); + return NULL; + } + const FilePath sub_dir = FilePath().AppendASCII(name); + FilePath extension_dir; + if (!file_util::PathExists(base_dir) && + !file_util::CreateDirectory(base_dir) && + !file_util::CreateTemporaryDirInDir( + base_dir, sub_dir.value(), &extension_dir)) { + ADD_FAILURE(); + return NULL; + } + std::string error; + scoped_refptr<Extension> extension = + Extension::Create(extension_dir, Extension::INTERNAL, + source, Extension::STRICT_ERROR_CHECKS, &error); + if (!error.empty()) { + ADD_FAILURE() << error; + return NULL; + } + if (!extension.get()) { + ADD_FAILURE(); + return NULL; + } + if (extension->name() != name) { + EXPECT_EQ(name, extension->name()); + return NULL; + } + if (extension->GetType() != type) { + EXPECT_EQ(type, extension->GetType()); + return NULL; + } + return extension; +} + +} // namespace + +scoped_refptr<Extension> SyncExtensionHelper::GetExtension( + Profile* profile, const std::string& name, + Extension::Type type) { + if (name.empty()) { + ADD_FAILURE(); + return NULL; + } + ProfileExtensionNameMap::iterator it = profile_extensions_.find(profile); + if (it == profile_extensions_.end()) { + ADD_FAILURE(); + return NULL; + } + ExtensionNameMap::const_iterator it2 = it->second.find(name); + if (it2 != it->second.end()) { + return it2->second; + } + + scoped_refptr<Extension> extension = + CreateExtension(profile->GetExtensionService()->install_directory(), + name, type); + if (!extension.get()) { + ADD_FAILURE(); + return NULL; + } + const std::string& expected_id = NameToId(name); + if (extension->id() != expected_id) { + EXPECT_EQ(expected_id, extension->id()); + return NULL; + } + VLOG(2) << "created extension with name = " + << name << ", id = " << expected_id; + (it->second)[name] = extension; + id_to_name_[expected_id] = name; + return extension; +} diff --git a/chrome/browser/sync/test/live_sync/sync_extension_helper.h b/chrome/browser/sync/test/live_sync/sync_extension_helper.h new file mode 100644 index 0000000..4aa3f1d --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sync_extension_helper.h @@ -0,0 +1,120 @@ +// Copyright (c) 2011 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_LIVE_SYNC_SYNC_EXTENSION_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_SYNC_EXTENSION_HELPER_H_ +#pragma once + +#include <map> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/memory/singleton.h" +#include "chrome/common/extensions/extension.h" + +class Extension; +class LiveSyncTest; +class Profile; + +class SyncExtensionHelper { + public: + // Singleton implementation. + static SyncExtensionHelper* GetInstance(); + + // Returns a generated extension ID for the given name. + static std::string NameToId(const std::string& name); + + // Initializes the profiles in |test| and registers them with + // internal data structures. + void SetupIfNecessary(LiveSyncTest* test); + + // Installs the extension with the given name to |profile|. + void InstallExtension( + Profile* profile, const std::string& name, Extension::Type type); + + // Uninstalls the extension with the given name from |profile|. + void UninstallExtension(Profile* profile, const std::string& name); + + // Returns a vector containing the names of all currently installed extensions + // on |profile|. + std::vector<std::string> GetInstalledExtensionNames(Profile* profile) const; + + // Enables the extension with the given name on |profile|. + void EnableExtension(Profile* profile, const std::string& name); + + // Disables the extension with the given name on |profile|. + void DisableExtension(Profile* profile, const std::string& name); + + // Returns true if the extension with the given name is enabled on |profile|. + bool IsExtensionEnabled(Profile* profile, const std::string& name) const; + + // Enables the extension with the given name to run in incognito mode + void IncognitoEnableExtension(Profile* profile, const std::string& name); + + // Disables the extension with the given name from running in incognito mode + void IncognitoDisableExtension(Profile* profile, const std::string& name); + + // Returns true iff the extension is enabled in incognito mode on |profile|. + bool IsIncognitoEnabled(Profile* profile, const std::string& name) const; + + // Returns true iff the extension with the given id is pending + // install in |profile|. + bool IsExtensionPendingInstallForSync( + Profile* profile, const std::string& id) const; + + // Installs all extensions pending sync in |profile| of the given + // type. + void InstallExtensionsPendingForSync(Profile* profile, Extension::Type type); + + // Returns true iff |profile1| and |profile2| have the same extensions and + // they are all in the same state. + static bool ExtensionStatesMatch(Profile* profile1, Profile* profile2); + + private: + struct ExtensionState { + enum EnabledState { DISABLED, PENDING, ENABLED }; + + ExtensionState(); + ~ExtensionState(); + bool Equals(const ExtensionState &other) const; + + EnabledState enabled_state; + bool incognito_enabled; + }; + + typedef std::map<std::string, ExtensionState> ExtensionStateMap; + typedef std::map<std::string, scoped_refptr<Extension> > ExtensionNameMap; + typedef std::map<Profile*, ExtensionNameMap> ProfileExtensionNameMap; + typedef std::map<std::string, std::string> StringMap; + + friend struct DefaultSingletonTraits<SyncExtensionHelper>; + + SyncExtensionHelper(); + ~SyncExtensionHelper(); + + // Returns a map from |profile|'s installed extensions to their state. + static ExtensionStateMap GetExtensionStates(Profile* profile); + + // Initializes extensions for |profile| and creates an entry in + // |profile_extensions_| for it. + void SetupProfile(Profile* profile); + + // Returns an extension for the given name in |profile|. type and + // index. Two extensions with the name but different profiles will + // have the same id. + scoped_refptr<Extension> GetExtension( + Profile* profile, const std::string& name, + Extension::Type type) WARN_UNUSED_RESULT; + + ProfileExtensionNameMap profile_extensions_; + StringMap id_to_name_; + bool setup_completed_; + + DISALLOW_COPY_AND_ASSIGN(SyncExtensionHelper); +}; + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_SYNC_EXTENSION_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/sync_integration_test.py b/chrome/browser/sync/test/live_sync/sync_integration_test.py new file mode 100644 index 0000000..17ed876 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/sync_integration_test.py @@ -0,0 +1,404 @@ +#!/usr/bin/python2.4 +# +# Copyright 2009 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. + + +"""A tool to run a chrome sync integration test, used by the buildbot slaves. + + When this is run, the current directory (cwd) should be the outer build + directory (e.g., chrome-release/build/). + + For a list of command-line options, call this script with '--help'. +""" + +__author__ = 'tejasshah@chromium.org' + + +import logging +import optparse +import os +import re +import subprocess +import sys +import tempfile +import time +import urllib2 + + +USAGE = '%s [options] [test args]' % os.path.basename(sys.argv[0]) +HTTP_SERVER_URL = None +HTTP_SERVER_PORT = None + + +class PathNotFound(Exception): pass + + +def ListSyncTests(test_exe_path): + """Returns list of the enabled live sync tests. + + Args: + test_exe_path: Absolute path to test exe file. + + Returns: + List of the tests that should be run. + """ + command = [test_exe_path] + command.append('--gtest_list_tests') + proc = subprocess.Popen( + command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1) + proc.wait() + sys.stdout.flush() + test_list = [] + for line in proc.stdout.readlines(): + if not line.strip(): + continue + elif line.count("."): # A new test collection + test_collection = line.split(".")[0].strip(); + else: # An individual test to run + test_name = line.strip() + test_list.append("%s.%s" % (test_collection, test_name)) + logging.info('List of tests to run: %s' % (test_list)) + return test_list + + +def GetUrl(command, port): + """Prepares the URL with appropriate command to send it to http server. + + Args: + command: Command for HTTP server + port: Port number as a parameter to the command + + Returns: + Formulated URL with the command and parameter. + """ + command_url = ( + '%s:%s/%s?port=%s' + % (HTTP_SERVER_URL, HTTP_SERVER_PORT, command, port)) + return command_url + + +def StartSyncServer(port=None): + """Starts a chrome sync server. + + Args: + port: Port number on which sync server to start + (Default value none, in this case it uses random port). + + Returns: + If success then port number on which sync server started, else None. + """ + sync_port = None + if port: + start_sync_server_url = GetUrl('startsyncserver', port) + else: + start_sync_server_url = ( + '%s:%s/%s' % (HTTP_SERVER_URL, HTTP_SERVER_PORT, 'startsyncserver')) + req = urllib2.Request(start_sync_server_url) + try: + response = urllib2.urlopen(req) + except urllib2.HTTPError, e: + logging.error( + 'Could not start sync server, something went wrong.' + 'Request URL: %s , Error Code: %s'% (start_sync_server_url, e.code)) + return sync_port + except urllib2.URLError, e: + logging.error( + 'Failed to reach HTTP server.Request URL: %s , Error: %s' + % (start_sync_server_url, e.reason)) + return sync_port + else: + # Let's read response and parse the sync server port number. + output = response.readlines() + # Regex to ensure that sync server started and extract the port number. + regex = re.compile( + ".*not.*running.*on.*port\s*:\s*(\d+).*started.*new.*sync.*server", + re.IGNORECASE|re.MULTILINE|re.DOTALL) + r = regex.search(output[0]) + if r: + sync_port = r.groups()[0] + if sync_port: + logging.info( + 'Started Sync Server Successfully on Port:%s. Request URL: %s , ' + 'Response: %s' % (sync_port, start_sync_server_url, output)) + response.fp._sock.recv = None + response.close() + return sync_port + + +def CheckIfSyncServerRunning(port): + """Check the healthz status of a chrome sync server. + + Args: + port: Port number on which sync server is running + + Returns: + True: If sync server running. + False: Otherwise. + """ + sync_server_healthz_url = ('%s:%s/healthz' % (HTTP_SERVER_URL, port)) + req = urllib2.Request(sync_server_healthz_url) + try: + response = urllib2.urlopen(req) + except urllib2.HTTPError, e: + logging.error( + 'It seems like Sync Server is not running, healthz check failed.' + 'Request URL: %s , Error Code: %s'% (sync_server_healthz_url, e.code)) + return False + except urllib2.URLError, e: + logging.error( + 'Failed to reach Sync server, healthz check failed.' + 'Request URL: %s , Error: %s'% (sync_server_healthz_url, e.reason)) + return False + else: + logging.info( + 'Sync Server healthz check Passed.Request URL: %s , Response: %s' + % (sync_server_healthz_url, response.readlines())) + response.fp._sock.recv = None + response.close() + return True + + +def StopSyncServer(port): + """Stops a chrome sync server. + + Args: + port: Port number on which sync server to Stop + + Returns: + Success/Failure as a bool value. + """ + stop_sync_server_url = GetUrl('stopsyncserver', port) + req = urllib2.Request(stop_sync_server_url) + logging.info("Stopping: %s" % stop_sync_server_url) + try: + response = urllib2.urlopen(req) + except urllib2.HTTPError, e: + logging.error( + 'Could not stop sync server, something went wrong.' + 'Request URL: %s , Error Code: %s'% (stop_sync_server_url, e.code)) + return False + except urllib2.URLError, e: + logging.error( + 'Failed to reach HTTP server.Request URL: %s , Error: %s' + % (stop_sync_server_url, e.reason)) + return False + else: + logging.info( + 'Stopped Sync Server Successfully.Request URL: %s , Response: %s' + % (stop_sync_server_url, response.readlines())) + response.fp._sock.recv = None + response.close() + return True + + +def ShowGtestLikeFailure(test_exe_path, test_name): + """Show a gtest-like error when the test can't be run for some reason. + + The scripts responsible for detecting test failures watch for this pattern. + + Args: + test_exe_path: Absolute path to the test exe file. + test_name: The name of the test that wasn't run. + """ + print '[ RUN ] %s.%s' % (os.path.basename(test_exe_path), test_name) + print '[ FAILED ] %s.%s' % (os.path.basename(test_exe_path), test_name) + + +def RunCommand(command): + """Runs the command list, printing its output and returning its exit status. + + Prints the given command (which should be a list of one or more strings), + then runs it and prints its stdout and stderr together to stdout, + line-buffered, converting line endings to CRLF (see note below). Waits for + the command to terminate and returns its status. + + Args: + command: Command to run. + + Returns: + Process exit code. + """ + print '\n' + subprocess.list2cmdline(command) + '\n', + proc = subprocess.Popen(command, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, bufsize=1) + last_flush_time = time.time() + while proc.poll() == None: + # Note that Windows Python converts \n to \r\n automatically whenever it + # encounters it written to a text file (including stdout). The only way + # around it is to write to a binary file, which isn't feasible for stdout. + # So we're stuck with \r\n here even though we explicitly write \n. (We + # could write \r instead, which doesn't get converted to \r\n, but that's + # probably more troublesome for people trying to read the files.) + line = proc.stdout.readline() + if line: + # The comma at the end tells python to not add \n, which is \r\n on + # Windows. + print line.rstrip() + '\n', + # Python on windows writes the buffer only when it reaches 4k. This is + # not fast enough. Flush each 10 seconds instead. + if time.time() - last_flush_time >= 10: + sys.stdout.flush() + last_flush_time = time.time() + sys.stdout.flush() + # Write the remaining buffer. + for line in proc.stdout.readlines(): + print line.rstrip() + '\n', + sys.stdout.flush() + return proc.returncode + + +def RunOneTest(test_exe_path, test_name, username, password): + """Run one live sync test after setting up a fresh server environment. + + Args: + test_exe_path: Absolute path to test exe file. + test_name: the name of the one test to run. + username: test account username. + password: test account password. + + Returns: + Zero for suceess. + Non-zero for failure. + """ + def LogTestNotRun(message): + ShowGtestLikeFailure(test_exe_path, test_name) + logging.info('\n\n%s did not run because %s' % (test_name, message)) + + try: + logging.info('\n\n*************************************') + logging.info('%s Start' % (test_name)) + sync_port = StartSyncServer() + if not sync_port: + LogTestNotRun('starting the sync server failed.') + return 1 + if not CheckIfSyncServerRunning(sync_port): + LogTestNotRun('sync server running check failed.') + return 1 + logging.info('Verified that sync server is running on port: %s', sync_port) + user_dir = GenericSetup(test_name) + logging.info('Created user data dir %s' % (user_dir)) + command = [ + test_exe_path, + '--gtest_filter='+ test_name, + '--user-data-dir=' + user_dir, + '--sync-user-for-test=' + username, + '--sync-password-for-test=' + password, + '--sync-url=' + HTTP_SERVER_URL + ':' + sync_port] + logging.info( + '%s will run with command: %s' + % (test_name, subprocess.list2cmdline(command))) + result = RunCommand(command) + StopSyncServer(sync_port) + return result + finally: + logging.info('%s End' % (test_name)) + + +def GenericSetup(test_name): + """Generic setup for running one test. + + Args: + test_name: The name of a test that is about to be run. + + Returns: + user_dir: Absolute path to user data dir created for the test. + """ + user_dir = tempfile.mkdtemp(prefix=test_name + '.') + return user_dir + + +def main_win(options, args): + """Main Function for win32 platform which drives the test here. + + Using the target build configuration, run the executable given in the + first non-option argument, passing any following arguments to that + executable. + + Args: + options: Option parameters. + args: Test arguments. + + Returns: + Result: Zero for success/ Non-zero for failure. + """ + final_result = 0 + test_exe = 'sync_integration_tests.exe' + build_dir = os.path.abspath(options.build_dir) + test_exe_path = os.path.join(build_dir, options.target, test_exe) + if not os.path.exists(test_exe_path): + raise PathNotFound('Unable to find %s' % test_exe_path) + test_list = ListSyncTests(test_exe_path) + for test_name in test_list: + result = RunOneTest( + test_exe_path, test_name, options.sync_test_username, + options.sync_test_password) + # If any single test fails then final result should be failure + if result != 0: + final_result = result + return final_result + +if '__main__' == __name__: + # Initialize logging. + log_level = logging.INFO + logging.basicConfig( + level=log_level, format='%(asctime)s %(filename)s:%(lineno)-3d' + ' %(levelname)s %(message)s', datefmt='%y%m%d %H:%M:%S') + + option_parser = optparse.OptionParser(usage=USAGE) + + # Since the trailing program to run may have has command-line args of its + # own, we need to stop parsing when we reach the first positional argument. + option_parser.disable_interspersed_args() + + option_parser.add_option( + '', '--target', default='Release', help='Build target (Debug or Release)' + ' Default value Release.') + option_parser.add_option( + '', '--build-dir', help='Path to main build directory' + '(the parent of the Release or Debug directory).') + option_parser.add_option( + '', '--http-server-url', help='Path to http server that can be used to' + ' start/stop sync server e.g. http://http_server_url_without_port') + option_parser.add_option( + '', '--http-server-port', help='Port on which http server is running' + ' e.g. 1010') + option_parser.add_option( + '', '--sync-test-username', help='Test username e.g. foo@gmail.com') + option_parser.add_option( + '', '--sync-test-password', help='Password for the test account') + options, args = option_parser.parse_args() + if not options.sync_test_password: + # Check along side this script under src/ first, and then check in + # the user profile dir. + password_file_path = os.path.join( + os.path.dirname(__file__),'sync_password') + if (not os.path.exists(password_file_path)): + password_file_path = os.path.join( + os.environ['USERPROFILE'], 'sync_password') + + if os.path.exists(password_file_path): + fs = open(password_file_path, 'r') + lines = fs.readlines() + if len(lines)==1: + options.sync_test_password = lines[0].strip() + else: + sys.stderr.write('sync_password file is not in required format.\n') + sys.exit(1) + else: + sys.stderr.write( + 'Missing required parameter- sync_test_password, please fix it.\n') + sys.exit(1) + if (not options.build_dir or not options.http_server_url or + not options.http_server_port or not options.sync_test_username): + sys.stderr.write('Missing required parameter, please fix it.\n') + option_parser.print_help() + sys.exit(1) + if sys.platform == 'win32': + HTTP_SERVER_URL = options.http_server_url + HTTP_SERVER_PORT = options.http_server_port + sys.exit(main_win(options, args)) + else: + sys.stderr.write('Unknown sys.platform value %s\n' % repr(sys.platform)) + sys.exit(1) diff --git a/chrome/browser/sync/test/live_sync/themes_helper.cc b/chrome/browser/sync/test/live_sync/themes_helper.cc new file mode 100644 index 0000000..8956340 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/themes_helper.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2011 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/live_sync/themes_helper.h" + +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "chrome/browser/sync/test/live_sync/sync_extension_helper.h" + +using sync_datatype_helper::test; + +namespace { + +// Make a name to pass to an extension helper. +std::string MakeName(int index) { + return "faketheme" + base::IntToString(index); +} + +ThemeService* GetThemeService(Profile* profile) { + return ThemeServiceFactory::GetForProfile(profile); +} + +} // namespace + +namespace themes_helper { + +std::string GetCustomTheme(int index) { + return SyncExtensionHelper::GetInstance()->NameToId(MakeName(index)); +} + +std::string GetThemeID(Profile* profile) { + return GetThemeService(profile)->GetThemeID(); +} + +bool UsingCustomTheme(Profile* profile) { + return GetThemeID(profile) != ThemeService::kDefaultThemeID; +} + +bool UsingDefaultTheme(Profile* profile) { + return GetThemeService(profile)->UsingDefaultTheme(); +} + +bool UsingNativeTheme(Profile* profile) { + return GetThemeService(profile)->UsingNativeTheme(); +} + +bool ThemeIsPendingInstall(Profile* profile, const std::string& id) { + return SyncExtensionHelper::GetInstance()-> + IsExtensionPendingInstallForSync(profile, id); +} + +bool HasOrWillHaveCustomTheme(Profile* profile, const std::string& id) { + return (GetThemeID(profile) == id) || ThemeIsPendingInstall(profile, id); +} + +void UseCustomTheme(Profile* profile, int index) { + SyncExtensionHelper::GetInstance()->InstallExtension( + profile, MakeName(index), Extension::TYPE_THEME); +} + +void UseDefaultTheme(Profile* profile) { + GetThemeService(profile)->UseDefaultTheme(); +} + +void UseNativeTheme(Profile* profile) { + // TODO(akalin): Fix this inconsistent naming in the theme service. + GetThemeService(profile)->SetNativeTheme(); +} + +} // namespace themes_helper diff --git a/chrome/browser/sync/test/live_sync/themes_helper.h b/chrome/browser/sync/test/live_sync/themes_helper.h new file mode 100644 index 0000000..6e28d1a --- /dev/null +++ b/chrome/browser/sync/test/live_sync/themes_helper.h @@ -0,0 +1,55 @@ +// Copyright (c) 2011 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_LIVE_SYNC_THEMES_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_THEMES_HELPER_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +class Profile; + +namespace themes_helper { + +// Gets the unique ID of the custom theme with the given index. +std::string GetCustomTheme(int index) WARN_UNUSED_RESULT; + +// Gets the ID of |profile|'s theme. +std::string GetThemeID(Profile* profile) WARN_UNUSED_RESULT; + +// Returns true iff |profile| is using a custom theme. +bool UsingCustomTheme(Profile* profile) WARN_UNUSED_RESULT; + +// Returns true iff |profile| is using the default theme. +bool UsingDefaultTheme(Profile* profile) WARN_UNUSED_RESULT; + +// Returns true iff |profile| is using the native theme. +bool UsingNativeTheme(Profile* profile) WARN_UNUSED_RESULT; + +// Returns true iff a theme with the given ID is pending install in +// |profile|. +bool ThemeIsPendingInstall( + Profile* profile, const std::string& id) WARN_UNUSED_RESULT; + +// Returns true iff |profile|'s current theme is the given +// custom theme or if the given theme is pending install. +bool HasOrWillHaveCustomTheme( + Profile* profile, const std::string& id) WARN_UNUSED_RESULT; + +// Sets |profile| to use the custom theme with the given index. +void UseCustomTheme(Profile* profile, int index); + +// Sets |profile| to use the default theme. +void UseDefaultTheme(Profile* profile); + +// Sets |profile| to use the native theme. +void UseNativeTheme(Profile* profile); + +} // namespace themes_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_THEMES_HELPER_H_ diff --git a/chrome/browser/sync/test/live_sync/two_client_apps_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_apps_sync_test.cc new file mode 100644 index 0000000..d6c48ea --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_apps_sync_test.cc @@ -0,0 +1,280 @@ +// Copyright (c) 2011 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/basictypes.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/apps_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using apps_helper::AllProfilesHaveSameAppsAsVerifier; +using apps_helper::DisableApp; +using apps_helper::EnableApp; +using apps_helper::HasSameAppsAsVerifier; +using apps_helper::IncognitoDisableApp; +using apps_helper::IncognitoEnableApp; +using apps_helper::InstallApp; +using apps_helper::InstallAppsPendingForSync; +using apps_helper::UninstallApp; + +class TwoClientAppsSyncTest : public LiveSyncTest { + public: + TwoClientAppsSyncTest() : LiveSyncTest(TWO_CLIENT) {} + + virtual ~TwoClientAppsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientAppsSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithNoApps) { + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithSameApps) { + ASSERT_TRUE(SetupClients()); + + const int kNumApps = 5; + for (int i = 0; i < kNumApps; ++i) { + InstallApp(GetProfile(0), i); + InstallApp(GetProfile(1), i); + InstallApp(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithDifferentApps) { + ASSERT_TRUE(SetupClients()); + + int i = 0; + + const int kNumCommonApps = 5; + for (int j = 0; j < kNumCommonApps; ++i, ++j) { + InstallApp(GetProfile(0), i); + InstallApp(GetProfile(1), i); + InstallApp(verifier(), i); + } + + const int kNumProfile0Apps = 10; + for (int j = 0; j < kNumProfile0Apps; ++i, ++j) { + InstallApp(GetProfile(0), i); + InstallApp(verifier(), i); + } + + const int kNumProfile1Apps = 10; + for (int j = 0; j < kNumProfile1Apps; ++i, ++j) { + InstallApp(GetProfile(1), i); + InstallApp(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AwaitQuiescence()); + + InstallAppsPendingForSync(GetProfile(0)); + InstallAppsPendingForSync(GetProfile(1)); + + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, InstallDifferentApps) { + ASSERT_TRUE(SetupClients()); + + int i = 0; + + const int kNumCommonApps = 5; + for (int j = 0; j < kNumCommonApps; ++i, ++j) { + InstallApp(GetProfile(0), i); + InstallApp(GetProfile(1), i); + InstallApp(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AwaitQuiescence()); + + const int kNumProfile0Apps = 10; + for (int j = 0; j < kNumProfile0Apps; ++i, ++j) { + InstallApp(GetProfile(0), i); + InstallApp(verifier(), i); + } + + const int kNumProfile1Apps = 10; + for (int j = 0; j < kNumProfile1Apps; ++i, ++j) { + InstallApp(GetProfile(1), i); + InstallApp(verifier(), i); + } + + ASSERT_TRUE(AwaitQuiescence()); + + InstallAppsPendingForSync(GetProfile(0)); + InstallAppsPendingForSync(GetProfile(1)); + + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TCM ID - 3711279. +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Add) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + InstallApp(GetProfile(0), 0); + InstallApp(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + + InstallAppsPendingForSync(GetProfile(0)); + InstallAppsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TCM ID - 3706267. +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Uninstall) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + InstallApp(GetProfile(0), 0); + InstallApp(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + + InstallAppsPendingForSync(GetProfile(0)); + InstallAppsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + UninstallApp(GetProfile(0), 0); + UninstallApp(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TCM ID - 3699295. +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Merge) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + InstallApp(GetProfile(0), 0); + InstallApp(GetProfile(1), 0); + ASSERT_TRUE(AwaitQuiescence()); + + UninstallApp(GetProfile(0), 0); + InstallApp(GetProfile(0), 1); + InstallApp(verifier(), 1); + + InstallApp(GetProfile(0), 2); + InstallApp(GetProfile(1), 2); + InstallApp(verifier(), 2); + + InstallApp(GetProfile(1), 3); + InstallApp(verifier(), 3); + + ASSERT_TRUE(AwaitQuiescence()); + InstallAppsPendingForSync(GetProfile(0)); + InstallAppsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TCM ID - 7723126. +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateEnableDisableApp) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + InstallApp(GetProfile(0), 0); + InstallApp(GetProfile(1), 0); + InstallApp(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + DisableApp(GetProfile(0), 0); + DisableApp(verifier(), 0); + ASSERT_TRUE(HasSameAppsAsVerifier(0)); + ASSERT_FALSE(HasSameAppsAsVerifier(1)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + EnableApp(GetProfile(1), 0); + EnableApp(verifier(), 0); + ASSERT_TRUE(HasSameAppsAsVerifier(1)); + ASSERT_FALSE(HasSameAppsAsVerifier(0)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TCM ID - 7706637. +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateIncognitoEnableDisable) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + InstallApp(GetProfile(0), 0); + InstallApp(GetProfile(1), 0); + InstallApp(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + IncognitoEnableApp(GetProfile(0), 0); + IncognitoEnableApp(verifier(), 0); + ASSERT_TRUE(HasSameAppsAsVerifier(0)); + ASSERT_FALSE(HasSameAppsAsVerifier(1)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + IncognitoDisableApp(GetProfile(1), 0); + IncognitoDisableApp(verifier(), 0); + ASSERT_TRUE(HasSameAppsAsVerifier(1)); + ASSERT_FALSE(HasSameAppsAsVerifier(0)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TCM ID - 3718276. +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, DisableApps) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForDatatype(syncable::APPS)); + InstallApp(GetProfile(0), 0); + InstallApp(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(HasSameAppsAsVerifier(0)); + ASSERT_FALSE(HasSameAppsAsVerifier(1)); + + ASSERT_TRUE(GetClient(1)->EnableSyncForDatatype(syncable::APPS)); + ASSERT_TRUE(AwaitQuiescence()); + + InstallAppsPendingForSync(GetProfile(0)); + InstallAppsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TCM ID - 3720303. +IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, DisableSync) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForAllDatatypes()); + InstallApp(GetProfile(0), 0); + InstallApp(verifier(), 0); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Installed an app.")); + ASSERT_TRUE(HasSameAppsAsVerifier(0)); + ASSERT_FALSE(HasSameAppsAsVerifier(1)); + + ASSERT_TRUE(GetClient(1)->EnableSyncForAllDatatypes()); + ASSERT_TRUE(AwaitQuiescence()); + + InstallAppsPendingForSync(GetProfile(0)); + InstallAppsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier()); +} + +// TODO(akalin): Add tests exercising: +// - Offline installation/uninstallation behavior +// - App-specific properties diff --git a/chrome/browser/sync/test/live_sync/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_autofill_sync_test.cc new file mode 100644 index 0000000..1978a61 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_autofill_sync_test.cc @@ -0,0 +1,409 @@ +// Copyright (c) 2011 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/utf_string_conversions.h" +#include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/autofill_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/webdata/autofill_entry.h" + +using autofill_helper::AddKeys; +using autofill_helper::AddProfile; +using autofill_helper::CreateAutofillProfile; +using autofill_helper::GetAllKeys; +using autofill_helper::GetAllProfiles; +using autofill_helper::KeysMatch; +using autofill_helper::ProfilesMatch; +using autofill_helper::PROFILE_FRASIER; +using autofill_helper::PROFILE_HOMER; +using autofill_helper::PROFILE_MARION; +using autofill_helper::PROFILE_NULL; +using autofill_helper::RemoveKey; +using autofill_helper::RemoveProfile; +using autofill_helper::UpdateProfile; + +// Autofill entry length is limited to 1024. See http://crbug.com/49332. +const size_t kMaxDataLength = 1024; + +class TwoClientAutofillSyncTest : public LiveSyncTest { + public: + TwoClientAutofillSyncTest() : LiveSyncTest(TWO_CLIENT) {} + virtual ~TwoClientAutofillSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientAutofillSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, WebDataServiceSanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Client0 adds a key. + std::set<AutofillKey> keys; + keys.insert(AutofillKey("name0", "value0")); + AddKeys(0, keys); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(KeysMatch(0, 1)); + ASSERT_EQ(1U, GetAllKeys(0).size()); + + // Client1 adds a key. + keys.clear(); + keys.insert(AutofillKey("name1", "value1-0")); + AddKeys(1, keys); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(KeysMatch(0, 1)); + ASSERT_EQ(2U, GetAllKeys(0).size()); + + // Client0 adds a key with the same name. + keys.clear(); + keys.insert(AutofillKey("name1", "value1-1")); + AddKeys(0, keys); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(KeysMatch(0, 1)); + ASSERT_EQ(3U, GetAllKeys(0).size()); + + // Client1 removes a key. + RemoveKey(1, AutofillKey("name1", "value1-0")); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(KeysMatch(0, 1)); + ASSERT_EQ(2U, GetAllKeys(0).size()); + + // Client0 removes the rest. + RemoveKey(0, AutofillKey("name0", "value0")); + RemoveKey(0, AutofillKey("name1", "value1-1")); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(KeysMatch(0, 1)); + ASSERT_EQ(0U, GetAllKeys(0).size()); +} + +// TCM ID - 3678296. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, AddUnicodeProfile) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + std::set<AutofillKey> keys; + keys.insert(AutofillKey(WideToUTF16(L"Sigur R\u00F3s"), + WideToUTF16(L"\u00C1g\u00E6tis byrjun"))); + AddKeys(0, keys); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(KeysMatch(0, 1)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, + AddDuplicateNamesToSameProfile) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + std::set<AutofillKey> keys; + keys.insert(AutofillKey("name0", "value0-0")); + keys.insert(AutofillKey("name0", "value0-1")); + keys.insert(AutofillKey("name1", "value1")); + AddKeys(0, keys); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(KeysMatch(0, 1)); + ASSERT_EQ(2U, GetAllKeys(0).size()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, + AddDuplicateNamesToDifferentProfiles) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + std::set<AutofillKey> keys0; + keys0.insert(AutofillKey("name0", "value0-0")); + keys0.insert(AutofillKey("name1", "value1")); + AddKeys(0, keys0); + + std::set<AutofillKey> keys1; + keys1.insert(AutofillKey("name0", "value0-1")); + keys1.insert(AutofillKey("name2", "value2")); + keys1.insert(AutofillKey("name3", "value3")); + AddKeys(1, keys1); + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(KeysMatch(0, 1)); + ASSERT_EQ(5U, GetAllKeys(0).size()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, + PersonalDataManagerSanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Client0 adds a profile. + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + // Client1 adds a profile. + AddProfile(1, CreateAutofillProfile(PROFILE_MARION)); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(2U, GetAllProfiles(0).size()); + + // Client0 adds the same profile. + AddProfile(0, CreateAutofillProfile(PROFILE_MARION)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(2U, GetAllProfiles(0).size()); + + // Client1 removes a profile. + RemoveProfile(1, GetAllProfiles(1)[0]->guid()); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + // Client0 updates a profile. + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(NAME_FIRST), + ASCIIToUTF16("Bart")); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + // Client1 removes remaining profile. + RemoveProfile(1, GetAllProfiles(1)[0]->guid()); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(0U, GetAllProfiles(0).size()); +} + +// TCM ID - 7261786. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, AddDuplicateProfiles) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); +} + +// TCM ID - 3636294. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, SameProfileWithConflict) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + AutofillProfile profile0 = CreateAutofillProfile(PROFILE_HOMER); + AutofillProfile profile1 = CreateAutofillProfile(PROFILE_HOMER); + profile1.SetInfo(PHONE_FAX_WHOLE_NUMBER, ASCIIToUTF16("1234567890")); + + AddProfile(0, profile0); + AddProfile(1, profile1); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); +} + +// TCM ID - 3626291. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, AddEmptyProfile) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_NULL)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(0U, GetAllProfiles(0).size()); +} + +// TCM ID - 3616283. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, AddProfile) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); +} + +// TCM ID - 3632260. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, AddMultipleProfiles) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + AddProfile(0, CreateAutofillProfile(PROFILE_MARION)); + AddProfile(0, CreateAutofillProfile(PROFILE_FRASIER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(3U, GetAllProfiles(0).size()); +} + +// TCM ID - 3602257. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, DeleteProfile) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + RemoveProfile(1, GetAllProfiles(1)[0]->guid()); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(0U, GetAllProfiles(0).size()); +} + +// TCM ID - 3627300. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, MergeProfiles) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + AddProfile(1, CreateAutofillProfile(PROFILE_MARION)); + AddProfile(1, CreateAutofillProfile(PROFILE_FRASIER)); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(3U, GetAllProfiles(0).size()); +} + +// TCM ID - 3665264. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, UpdateFields) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(NAME_FIRST), + ASCIIToUTF16("Lisa")); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(EMAIL_ADDRESS), + ASCIIToUTF16("grrrl@TV.com")); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); +} + +// TCM ID - 3628299. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, ConflictingFields) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(NAME_FIRST), + ASCIIToUTF16("Lisa")); + UpdateProfile(1, + GetAllProfiles(1)[0]->guid(), + AutofillType(NAME_FIRST), + ASCIIToUTF16("Bart")); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); +} + +// TCM ID - 3663293. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, DisableAutofill) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncable::AUTOFILL)); + AddProfile(0, CreateAutofillProfile(PROFILE_FRASIER)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_FALSE(ProfilesMatch(0, 1)); + ASSERT_EQ(2U, GetAllProfiles(0).size()); + ASSERT_EQ(1U, GetAllProfiles(1).size()); + + ASSERT_TRUE(GetClient(0)->EnableSyncForDatatype(syncable::AUTOFILL)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(2U, GetAllProfiles(0).size()); +} + +// TCM ID - 3661291. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, DisableSync) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForAllDatatypes()); + AddProfile(0, CreateAutofillProfile(PROFILE_FRASIER)); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Added a profile.")); + ASSERT_FALSE(ProfilesMatch(0, 1)); + ASSERT_EQ(2U, GetAllProfiles(0).size()); + ASSERT_EQ(1U, GetAllProfiles(1).size()); + + ASSERT_TRUE(GetClient(1)->EnableSyncForAllDatatypes()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(2U, GetAllProfiles(0).size()); +} + +// TCM ID - 3608295. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, MaxLength) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + string16 max_length_string(kMaxDataLength, '.'); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(NAME_FIRST), + max_length_string); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(NAME_LAST), + max_length_string); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(EMAIL_ADDRESS), + max_length_string); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(ADDRESS_HOME_LINE1), + max_length_string); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); +} + +// TODO(braffert): Remove FAILS annotation when crbug.com/85769 is resolved. +// TCM ID - 7735472. +IN_PROC_BROWSER_TEST_F(TwoClientAutofillSyncTest, FAILS_ExceedsMaxLength) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + AddProfile(0, CreateAutofillProfile(PROFILE_HOMER)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfilesMatch(0, 1)); + ASSERT_EQ(1U, GetAllProfiles(0).size()); + + string16 exceeds_max_length_string(kMaxDataLength + 1, '.'); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(NAME_FIRST), + exceeds_max_length_string); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(NAME_LAST), + exceeds_max_length_string); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(EMAIL_ADDRESS), + exceeds_max_length_string); + UpdateProfile(0, + GetAllProfiles(0)[0]->guid(), + AutofillType(ADDRESS_HOME_LINE1), + exceeds_max_length_string); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_FALSE(ProfilesMatch(0, 1)); +} diff --git a/chrome/browser/sync/test/live_sync/two_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_bookmarks_sync_test.cc new file mode 100644 index 0000000..869be0e --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_bookmarks_sync_test.cc @@ -0,0 +1,1757 @@ +// Copyright (c) 2011 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/rand_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/bookmarks_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using bookmarks_helper::AddFolder; +using bookmarks_helper::AddURL; +using bookmarks_helper::AllModelsMatch; +using bookmarks_helper::AllModelsMatchVerifier; +using bookmarks_helper::ContainsDuplicateBookmarks; +using bookmarks_helper::CountBookmarksWithTitlesMatching; +using bookmarks_helper::CreateFavicon; +using bookmarks_helper::GetBookmarkBarNode; +using bookmarks_helper::GetOtherNode; +using bookmarks_helper::GetUniqueNodeByURL; +using bookmarks_helper::IndexedFolderName; +using bookmarks_helper::IndexedSubfolderName; +using bookmarks_helper::IndexedSubsubfolderName; +using bookmarks_helper::IndexedURL; +using bookmarks_helper::IndexedURLTitle; +using bookmarks_helper::Move; +using bookmarks_helper::Remove; +using bookmarks_helper::ReverseChildOrder; +using bookmarks_helper::SetFavicon; +using bookmarks_helper::SetTitle; +using bookmarks_helper::SetURL; +using bookmarks_helper::SortChildren; + +const std::string kGenericURL = "http://www.host.ext:1234/path/filename"; +const std::wstring kGenericURLTitle = L"URL Title"; +const std::wstring kGenericFolderName = L"Folder Name"; +const std::wstring kGenericSubfolderName = L"Subfolder Name"; +const std::wstring kGenericSubsubfolderName = L"Subsubfolder Name"; + +class TwoClientBookmarksSyncTest : public LiveSyncTest { + public: + TwoClientBookmarksSyncTest() : LiveSyncTest(TWO_CLIENT) {} + virtual ~TwoClientBookmarksSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientBookmarksSyncTest); +}; + +const std::vector<unsigned char> GenericFavicon() { + return CreateFavicon(254); +} + +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, Sanity) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL google_url("http://www.google.com"); + ASSERT_TRUE(AddURL(0, L"Google", google_url) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AddURL(1, L"Yahoo", GURL("http://www.yahoo.com")) != NULL); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* new_folder = AddFolder(0, 2, L"New Folder"); + Move(0, GetUniqueNodeByURL(0, google_url), new_folder, 0); + SetTitle(0, GetBookmarkBarNode(0)->GetChild(0), L"Yahoo!!"); + ASSERT_TRUE(AddURL(0, GetBookmarkBarNode(0), 1, L"CNN", + GURL("http://www.cnn.com")) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(1, L"Facebook", GURL("http://www.facebook.com")) != NULL); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + SortChildren(1, GetBookmarkBarNode(1)); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + DisableVerifier(); + SetTitle(0, GetUniqueNodeByURL(0, google_url), L"Google++"); + SetTitle(1, GetUniqueNodeByURL(1, google_url), L"Google--"); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SimultaneousURLChanges) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL initial_url("http://www.google.com"); + GURL second_url("http://www.google.com/abc"); + GURL third_url("http://www.google.com/def"); + std::wstring title = L"Google"; + + ASSERT_TRUE(AddURL(0, title, initial_url) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + DisableVerifier(); + ASSERT_TRUE(SetURL( + 0, GetUniqueNodeByURL(0, initial_url), second_url) != NULL); + ASSERT_TRUE(SetURL( + 1, GetUniqueNodeByURL(1, initial_url), third_url) != NULL); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + + SetTitle(0, GetBookmarkBarNode(0)->GetChild(0), L"Google1"); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatch()); +} + +// Test Scribe ID - 370558. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_AddFirstFolder) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddFolder(0, kGenericFolderName) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370559. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_AddFirstBMWithoutFavicon) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370489. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_AddFirstBMWithFavicon) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* bookmark = AddURL(0, kGenericURLTitle, GURL(kGenericURL)); + ASSERT_TRUE(bookmark != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + SetFavicon(0, bookmark, GenericFavicon()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370560. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_AddNonHTTPBMs) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL( + 0, L"FTP URL", GURL("ftp://user:password@host:1234/path")) != NULL); + ASSERT_TRUE(AddURL(0, L"File URL", GURL("file://host/path")) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370561. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_AddFirstBMUnderFolder) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + ASSERT_TRUE(AddURL( + 0, folder, 0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370562. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_AddSeveralBMsUnderBMBarAndOtherBM) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 20; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + ASSERT_TRUE(AddURL( + 0, GetOtherNode(0), i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370563. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_AddSeveralBMsAndFolders) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 15; ++i) { + if (base::RandDouble() > 0.6) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } else { + std::wstring title = IndexedFolderName(i); + const BookmarkNode* folder = AddFolder(0, i, title); + ASSERT_TRUE(folder != NULL); + if (base::RandDouble() > 0.4) { + for (int i = 0; i < 20; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE( + AddURL(0, folder, i, title, url) != NULL); + } + } + } + } + for (int i = 0; i < 10; i++) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, GetOtherNode(0), i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370641. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DuplicateBMWithDifferentURLSameName) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL url0 = GURL(IndexedURL(0)); + GURL url1 = GURL(IndexedURL(1)); + ASSERT_TRUE(AddURL(0, kGenericURLTitle, url0) != NULL); + ASSERT_TRUE(AddURL(0, kGenericURLTitle, url1) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 370639 - Add bookmarks with different name and same URL. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DuplicateBookmarksWithSameURL) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring title0 = IndexedURLTitle(0); + std::wstring title1 = IndexedURLTitle(1); + ASSERT_TRUE(AddURL(0, title0, GURL(kGenericURL)) != NULL); + ASSERT_TRUE(AddURL(0, title1, GURL(kGenericURL)) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371817. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMName) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring title = IndexedURLTitle(1); + const BookmarkNode* bookmark = AddURL(0, title, GURL(kGenericURL)); + ASSERT_TRUE(bookmark != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring new_title = IndexedURLTitle(2); + SetTitle(0, bookmark, new_title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371822. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMURL) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL url = GURL(IndexedURL(1)); + const BookmarkNode* bookmark = AddURL(0, kGenericURLTitle, url); + ASSERT_TRUE(bookmark != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL new_url = GURL(IndexedURL(2)); + ASSERT_TRUE(SetURL(0, bookmark, new_url) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + + +// Test Scribe ID - 371818 - Renaming the same bookmark name twice. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_TwiceRenamingBookmarkName) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring title = IndexedURLTitle(1); + const BookmarkNode* bookmark = AddURL(0, title, GURL(kGenericURL)); + ASSERT_TRUE(bookmark != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring new_title = IndexedURLTitle(2); + SetTitle(0, bookmark, new_title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + SetTitle(0, bookmark, title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371823 - Renaming the same bookmark URL twice. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_TwiceRenamingBookmarkURL) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL url = GURL(IndexedURL(1)); + const BookmarkNode* bookmark = AddURL(0, kGenericURLTitle, url); + ASSERT_TRUE(bookmark != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL new_url = GURL(IndexedURL(2)); + ASSERT_TRUE(SetURL(0, bookmark, new_url) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(SetURL(0, bookmark, url) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371824. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMFolder) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring title = IndexedFolderName(1); + const BookmarkNode* folder = AddFolder(0, title); + ASSERT_TRUE(AddURL( + 0, folder, 0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring new_title = IndexedFolderName(2); + SetTitle(0, folder, new_title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371825. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameEmptyBMFolder) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring title = IndexedFolderName(1); + const BookmarkNode* folder = AddFolder(0, title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring new_title = IndexedFolderName(2); + SetTitle(0, folder, new_title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371826. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_RenameBMFolderWithLongHierarchy) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring title = IndexedFolderName(1); + const BookmarkNode* folder = AddFolder(0, title); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 120; ++i) { + if (base::RandDouble() > 0.15) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } else { + std::wstring title = IndexedSubfolderName(i); + ASSERT_TRUE(AddFolder(0, folder, i, title) != NULL); + } + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring new_title = IndexedFolderName(2); + SetTitle(0, folder, new_title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371827. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_RenameBMFolderThatHasParentAndChildren) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 1; i < 15; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } + std::wstring title = IndexedSubfolderName(1); + const BookmarkNode* subfolder = AddFolder(0, folder, 0, title); + for (int i = 0; i < 120; ++i) { + if (base::RandDouble() > 0.15) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, subfolder, i, title, url) != NULL); + } else { + std::wstring title = IndexedSubsubfolderName(i); + ASSERT_TRUE(AddFolder(0, subfolder, i, title) != NULL); + } + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + std::wstring new_title = IndexedSubfolderName(2); + SetTitle(0, subfolder, new_title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371828. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMNameAndURL) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL url = GURL(IndexedURL(1)); + std::wstring title = IndexedURLTitle(1); + const BookmarkNode* bookmark = AddURL(0, title, url); + ASSERT_TRUE(bookmark != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL new_url = GURL(IndexedURL(2)); + std::wstring new_title = IndexedURLTitle(2); + bookmark = SetURL(0, bookmark, new_url); + ASSERT_TRUE(bookmark != NULL); + SetTitle(0, bookmark, new_title); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371832. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DeleteBMEmptyAccountAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL( + 0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, GetBookmarkBarNode(0), 0); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371833. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelBMNonEmptyAccountAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 20; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, GetBookmarkBarNode(0), 0); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371835. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelFirstBMUnderBMFoldNonEmptyFoldAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, folder, 0); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371836. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelLastBMUnderBMFoldNonEmptyFoldAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, folder, folder->child_count() - 1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371856. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelMiddleBMUnderBMFoldNonEmptyFoldAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, folder, 4); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371857. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelBMsUnderBMFoldEmptyFolderAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + int child_count = folder->child_count(); + for (int i = 0; i < child_count; ++i) { + Remove(0, folder, 0); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371858. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelEmptyBMFoldEmptyAccountAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddFolder(0, kGenericFolderName) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, GetBookmarkBarNode(0), 0); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371869. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelEmptyBMFoldNonEmptyAccountAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddFolder(0, kGenericFolderName) != NULL); + for (int i = 1; i < 15; ++i) { + if (base::RandDouble() > 0.6) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } else { + std::wstring title = IndexedFolderName(i); + ASSERT_TRUE(AddFolder(0, i, title) != NULL); + } + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, GetBookmarkBarNode(0), 0); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371879. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelBMFoldWithBMsNonEmptyAccountAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + const BookmarkNode* folder = AddFolder(0, 1, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 2; i < 10; ++i) { + if (base::RandDouble() > 0.6) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } else { + std::wstring title = IndexedFolderName(i); + ASSERT_TRUE(AddFolder(0, i, title) != NULL); + } + } + for (int i = 0; i < 15; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, GetBookmarkBarNode(0), 1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371880. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelBMFoldWithBMsAndBMFoldsNonEmptyACAfterwards) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + const BookmarkNode* folder = AddFolder(0, 1, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 2; i < 10; ++i) { + if (base::RandDouble() > 0.6) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } else { + std::wstring title = IndexedFolderName(i); + ASSERT_TRUE(AddFolder(0, i, title) != NULL); + } + } + for (int i = 0; i < 10; ++i) { + if (base::RandDouble() > 0.6) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } else { + std::wstring title = IndexedSubfolderName(i); + const BookmarkNode* subfolder = + AddFolder(0, folder, i, title); + ASSERT_TRUE(subfolder != NULL); + if (base::RandDouble() > 0.3) { + for (int j = 0; j < 10; ++j) { + if (base::RandDouble() > 0.6) { + std::wstring title = IndexedURLTitle(j); + GURL url = GURL(IndexedURL(j)); + ASSERT_TRUE(AddURL( + 0, subfolder, j, title, url) != NULL); + } else { + std::wstring title = IndexedSubsubfolderName(j); + ASSERT_TRUE(AddFolder( + 0, subfolder, j, title) != NULL); + } + } + } + } + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, GetBookmarkBarNode(0), 1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371882. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_DelBMFoldWithParentAndChildrenBMsAndBMFolds) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 1; i < 11; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } + const BookmarkNode* subfolder = + AddFolder(0, folder, 0, kGenericSubfolderName); + ASSERT_TRUE(subfolder != NULL); + for (int i = 0; i < 30; ++i) { + if (base::RandDouble() > 0.2) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, subfolder, i, title, url) != NULL); + } else { + std::wstring title = IndexedSubsubfolderName(i); + ASSERT_TRUE(AddFolder(0, subfolder, i, title) != NULL); + } + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Remove(0, folder, 0); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371931. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_ReverseTheOrderOfTwoBMs) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL url0 = GURL(IndexedURL(0)); + GURL url1 = GURL(IndexedURL(1)); + std::wstring title0 = IndexedURLTitle(0); + std::wstring title1 = IndexedURLTitle(1); + const BookmarkNode* bookmark0 = AddURL(0, 0, title0, url0); + const BookmarkNode* bookmark1 = AddURL(0, 1, title1, url1); + ASSERT_TRUE(bookmark0 != NULL); + ASSERT_TRUE(bookmark1 != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Move(0, bookmark0, GetBookmarkBarNode(0), 2); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371933. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_ReverseTheOrderOf10BMs) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + ReverseChildOrder(0, GetBookmarkBarNode(0)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371954. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_MovingBMsFromBMBarToBMFolder) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + const BookmarkNode* folder = AddFolder(0, 1, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 2; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + int num_bookmarks_to_move = + GetBookmarkBarNode(0)->child_count() - 2; + for (int i = 0; i < num_bookmarks_to_move; ++i) { + Move( + 0, GetBookmarkBarNode(0)->GetChild(2), folder, i); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + } +} + +// Test Scribe ID - 371957. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_MovingBMsFromBMFoldToBMBar) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(0, kGenericURLTitle, GURL(kGenericURL)) != NULL); + const BookmarkNode* folder = AddFolder(0, 1, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + int num_bookmarks_to_move = folder->child_count() - 2; + for (int i = 0; i < num_bookmarks_to_move; ++i) { + Move(0, folder->GetChild(0), GetBookmarkBarNode(0), i); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + } +} + +// Test Scribe ID - 371961. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_MovingBMsFromParentBMFoldToChildBMFold) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + const BookmarkNode* subfolder = + AddFolder(0, folder, 3, kGenericSubfolderName); + ASSERT_TRUE(subfolder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i + 3); + GURL url = GURL(IndexedURL(i + 3)); + ASSERT_TRUE(AddURL(0, subfolder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 3; ++i) { + GURL url = GURL(IndexedURL(i)); + Move(0, GetUniqueNodeByURL(0, url), subfolder, i + 10); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371964. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_MovingBMsFromChildBMFoldToParentBMFold) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + const BookmarkNode* subfolder = + AddFolder(0, folder, 3, kGenericSubfolderName); + ASSERT_TRUE(subfolder != NULL); + for (int i = 0; i < 5; ++i) { + std::wstring title = IndexedURLTitle(i + 3); + GURL url = GURL(IndexedURL(i + 3)); + ASSERT_TRUE(AddURL(0, subfolder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 3; ++i) { + GURL url = GURL(IndexedURL(i + 3)); + Move(0, GetUniqueNodeByURL(0, url), folder, i + 4); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371967. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_HoistBMs10LevelUp) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = GetBookmarkBarNode(0); + const BookmarkNode* folder_L0 = NULL; + const BookmarkNode* folder_L10 = NULL; + for (int level = 0; level < 15; ++level) { + int num_bookmarks = base::RandInt(0, 9); + for (int i = 0; i < num_bookmarks; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + std::wstring title = IndexedFolderName(level); + folder = AddFolder(0, folder, folder->child_count(), title); + ASSERT_TRUE(folder != NULL); + if (level == 0) folder_L0 = folder; + if (level == 10) folder_L10 = folder; + } + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i + 10); + GURL url = GURL(IndexedURL(i + 10)); + ASSERT_TRUE(AddURL(0, folder_L10, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL url10 = GURL(IndexedURL(10)); + Move(0, GetUniqueNodeByURL( + 0, url10), folder_L0, folder_L0->child_count()); + GURL url11 = GURL(IndexedURL(11)); + Move(0, GetUniqueNodeByURL(0, url11), folder_L0, 0); + GURL url12 = GURL(IndexedURL(12)); + Move(0, GetUniqueNodeByURL(0, url12), folder_L0, 1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371968. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_SinkBMs10LevelDown) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = GetBookmarkBarNode(0); + const BookmarkNode* folder_L0 = NULL; + const BookmarkNode* folder_L10 = NULL; + for (int level = 0; level < 15; ++level) { + int num_bookmarks = base::RandInt(0, 9); + for (int i = 0; i < num_bookmarks; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + std::wstring title = IndexedFolderName(level); + folder = AddFolder(0, folder, folder->child_count(), title); + ASSERT_TRUE(folder != NULL); + if (level == 0) folder_L0 = folder; + if (level == 10) folder_L10 = folder; + } + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i + 10); + GURL url = GURL(IndexedURL(i + 10)); + ASSERT_TRUE(AddURL(0, folder_L0, 0, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + GURL url10 = GURL(IndexedURL(10)); + Move(0, GetUniqueNodeByURL(0, url10), folder_L10, folder_L10->child_count()); + GURL url11 = GURL(IndexedURL(11)); + Move(0, GetUniqueNodeByURL(0, url11), folder_L10, 0); + GURL url12 = GURL(IndexedURL(12)); + Move(0, GetUniqueNodeByURL(0, url12), folder_L10, 1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371980. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_SinkEmptyBMFold5LevelsDown) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = GetBookmarkBarNode(0); + const BookmarkNode* folder_L5 = NULL; + for (int level = 0; level < 15; ++level) { + int num_bookmarks = base::RandInt(0, 9); + for (int i = 0; i < num_bookmarks; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + std::wstring title = IndexedFolderName(level); + folder = AddFolder( + 0, folder, folder->child_count(), title); + ASSERT_TRUE(folder != NULL); + if (level == 5) folder_L5 = folder; + } + folder = AddFolder( + 0, GetBookmarkBarNode(0)->child_count(), kGenericFolderName); + ASSERT_TRUE(folder != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Move(0, folder, folder_L5, folder_L5->child_count()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 371997. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_SinkNonEmptyBMFold5LevelsDown) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = GetBookmarkBarNode(0); + const BookmarkNode* folder_L5 = NULL; + for (int level = 0; level < 6; ++level) { + int num_bookmarks = base::RandInt(0, 9); + for (int i = 0; i < num_bookmarks; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + std::wstring title = IndexedFolderName(level); + folder = AddFolder(0, folder, folder->child_count(), title); + ASSERT_TRUE(folder != NULL); + if (level == 5) folder_L5 = folder; + } + folder = AddFolder( + 0, GetBookmarkBarNode(0)->child_count(), kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Move(0, folder, folder_L5, folder_L5->child_count()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 372006. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_HoistFolder5LevelsUp) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + const BookmarkNode* folder = GetBookmarkBarNode(0); + const BookmarkNode* folder_L5 = NULL; + for (int level = 0; level < 6; ++level) { + int num_bookmarks = base::RandInt(0, 9); + for (int i = 0; i < num_bookmarks; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + std::wstring title = IndexedFolderName(level); + folder = AddFolder( + 0, folder, folder->child_count(), title); + ASSERT_TRUE(folder != NULL); + if (level == 5) folder_L5 = folder; + } + folder = AddFolder( + 0, folder_L5, folder_L5->child_count(), kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + Move(0, folder, GetBookmarkBarNode(0), GetBookmarkBarNode(0)->child_count()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 372026. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_ReverseTheOrderOfTwoBMFolders) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 2; ++i) { + std::wstring title = IndexedFolderName(i); + const BookmarkNode* folder = AddFolder(0, i, title); + ASSERT_TRUE(folder != NULL); + for (int j = 0; j < 10; ++j) { + std::wstring title = IndexedURLTitle(j); + GURL url = GURL(IndexedURL(j)); + ASSERT_TRUE(AddURL(0, folder, j, title, url) != NULL); + } + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + ReverseChildOrder(0, GetBookmarkBarNode(0)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 372028. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SC_ReverseTheOrderOfTenBMFolders) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + for (int i = 0; i < 10; ++i) { + std::wstring title = IndexedFolderName(i); + const BookmarkNode* folder = AddFolder(0, i, title); + ASSERT_TRUE(folder != NULL); + for (int j = 0; j < 10; ++j) { + std::wstring title = IndexedURLTitle(1000 * i + j); + GURL url = GURL(IndexedURL(j)); + ASSERT_TRUE(AddURL(0, folder, j, title, url) != NULL); + } + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + + ReverseChildOrder(0, GetBookmarkBarNode(0)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 373379. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_BiDirectionalPushAddingBM) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + DisableVerifier(); + for (int i = 0; i < 2; ++i) { + std::wstring title0 = IndexedURLTitle(2*i); + GURL url0 = GURL(IndexedURL(2*i)); + ASSERT_TRUE(AddURL(0, title0, url0) != NULL); + std::wstring title1 = IndexedURLTitle(2*i+1); + GURL url1 = GURL(IndexedURL(2*i+1)); + ASSERT_TRUE(AddURL(1, title1, url1) != NULL); + } + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// Test Scribe ID - 373503. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_BiDirectionalPush_AddingSameBMs) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + // Note: When a racy commit is done with identical bookmarks, it is possible + // for duplicates to exist after sync completes. See http://crbug.com/19769. + DisableVerifier(); + for (int i = 0; i < 2; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, title, url) != NULL); + ASSERT_TRUE(AddURL(1, title, url) != NULL); + } + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); +} + +// Test Scribe ID - 373506. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_BootStrapEmptyStateEverywhere) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// Test Scribe ID - 373505. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_Merge_CaseInsensitivity_InNames) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + const BookmarkNode* folder0 = AddFolder(0, L"Folder"); + ASSERT_TRUE(folder0 != NULL); + ASSERT_TRUE(AddURL(0, folder0, 0, L"Bookmark 0", GURL(kGenericURL)) != NULL); + ASSERT_TRUE(AddURL(0, folder0, 1, L"Bookmark 1", GURL(kGenericURL)) != NULL); + ASSERT_TRUE(AddURL(0, folder0, 2, L"Bookmark 2", GURL(kGenericURL)) != NULL); + + const BookmarkNode* folder1 = AddFolder(1, L"fOlDeR"); + ASSERT_TRUE(folder1 != NULL); + ASSERT_TRUE(AddURL(1, folder1, 0, L"bOoKmArK 0", GURL(kGenericURL)) != NULL); + ASSERT_TRUE(AddURL(1, folder1, 1, L"BooKMarK 1", GURL(kGenericURL)) != NULL); + ASSERT_TRUE(AddURL(1, folder1, 2, L"bOOKMARK 2", GURL(kGenericURL)) != NULL); + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// Test Scribe ID - 373508. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_SimpleMergeOfDifferentBMModels) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + ASSERT_TRUE(AddURL(1, i, title, url) != NULL); + } + + for (int i = 3; i < 10; ++i) { + std::wstring title0 = IndexedURLTitle(i); + GURL url0 = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title0, url0) != NULL); + std::wstring title1 = IndexedURLTitle(i+7); + GURL url1 = GURL(IndexedURL(i+7)); + ASSERT_TRUE(AddURL(1, i, title1, url1) != NULL); + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// Test Scribe ID - 386586. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_MergeSimpleBMHierarchyUnderBMBar) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + ASSERT_TRUE(AddURL(1, i, title, url) != NULL); + } + + for (int i = 3; i < 10; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(1, i, title, url) != NULL); + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// Test Scribe ID - 386589. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_MergeSimpleBMHierarchyEqualSetsUnderBMBar) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + ASSERT_TRUE(AddURL(1, i, title, url) != NULL); + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// Test Scribe ID - 373504 - Merge bookmark folders with different bookmarks. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_MergeBMFoldersWithDifferentBMs) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + const BookmarkNode* folder0 = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder0 != NULL); + const BookmarkNode* folder1 = AddFolder(1, kGenericFolderName); + ASSERT_TRUE(folder1 != NULL); + for (int i = 0; i < 2; ++i) { + std::wstring title0 = IndexedURLTitle(2*i); + GURL url0 = GURL(IndexedURL(2*i)); + ASSERT_TRUE(AddURL(0, folder0, i, title0, url0) != NULL); + std::wstring title1 = IndexedURLTitle(2*i+1); + GURL url1 = GURL(IndexedURL(2*i+1)); + ASSERT_TRUE(AddURL(1, folder1, i, title1, url1) != NULL); + } + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// Test Scribe ID - 373509 - Merge moderately complex bookmark models. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_MergeDifferentBMModelsModeratelyComplex) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + for (int i = 0; i < 25; ++i) { + std::wstring title0 = IndexedURLTitle(i); + GURL url0 = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title0, url0) != NULL); + std::wstring title1 = IndexedURLTitle(i+50); + GURL url1 = GURL(IndexedURL(i+50)); + ASSERT_TRUE(AddURL(1, i, title1, url1) != NULL); + } + for (int i = 25; i < 30; ++i) { + std::wstring title0 = IndexedFolderName(i); + const BookmarkNode* folder0 = AddFolder(0, i, title0); + ASSERT_TRUE(folder0 != NULL); + std::wstring title1 = IndexedFolderName(i+50); + const BookmarkNode* folder1 = AddFolder(1, i, title1); + ASSERT_TRUE(folder1 != NULL); + for (int j = 0; j < 5; ++j) { + std::wstring title0 = IndexedURLTitle(i+5*j); + GURL url0 = GURL(IndexedURL(i+5*j)); + ASSERT_TRUE(AddURL(0, folder0, j, title0, url0) != NULL); + std::wstring title1 = IndexedURLTitle(i+5*j+50); + GURL url1 = GURL(IndexedURL(i+5*j+50)); + ASSERT_TRUE(AddURL(1, folder1, j, title1, url1) != NULL); + } + } + for (int i = 100; i < 125; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, title, url) != NULL); + ASSERT_TRUE(AddURL(1, title, url) != NULL); + } + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3675271 - Merge simple bookmark subset under bookmark folder. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_MergeSimpleBMHierarchySubsetUnderBMFolder) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + for (int i = 0; i < 2; ++i) { + const BookmarkNode* folder = AddFolder(i, kGenericFolderName); + ASSERT_TRUE(folder != NULL); + for (int j = 0; j < 4; ++j) { + if (base::RandDouble() < 0.5) { + std::wstring title = IndexedURLTitle(j); + GURL url = GURL(IndexedURL(j)); + ASSERT_TRUE(AddURL(i, folder, j, title, url) != NULL); + } else { + std::wstring title = IndexedFolderName(j); + ASSERT_TRUE(AddFolder(i, folder, j, title) != NULL); + } + } + } + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3727284 - Merge subsets of bookmark under bookmark bar. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_MergeSimpleBMHierarchySubsetUnderBookmarkBar) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + for (int i = 0; i < 4; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } + + for (int j = 0; j < 2; ++j) { + std::wstring title = IndexedURLTitle(j); + GURL url = GURL(IndexedURL(j)); + ASSERT_TRUE(AddURL(1, j, title, url) != NULL); + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); + ASSERT_FALSE(ContainsDuplicateBookmarks(1)); +} + +// TCM ID - 3659294 - Merge simple bookmark hierarchy under bookmark folder. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_Merge_SimpleBMHierarchy_Under_BMFolder) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + const BookmarkNode* folder0 = AddFolder(0, 0, kGenericFolderName); + ASSERT_TRUE(folder0 != NULL); + ASSERT_TRUE(AddURL( + 0, folder0, 0, IndexedURLTitle(1), GURL(IndexedURL(1))) != NULL); + ASSERT_TRUE(AddFolder(0, folder0, 1, IndexedSubfolderName(2)) != NULL); + ASSERT_TRUE(AddURL( + 0, folder0, 2, IndexedURLTitle(3), GURL(IndexedURL(3))) != NULL); + ASSERT_TRUE(AddFolder(0, folder0, 3, IndexedSubfolderName(4)) != NULL); + + const BookmarkNode* folder1 = AddFolder(1, 0, kGenericFolderName); + ASSERT_TRUE(folder1 != NULL); + ASSERT_TRUE(AddFolder(1, folder1, 0, IndexedSubfolderName(0)) != NULL); + ASSERT_TRUE(AddFolder(1, folder1, 1, IndexedSubfolderName(2)) != NULL); + ASSERT_TRUE(AddURL( + 1, folder1, 2, IndexedURLTitle(3), GURL(IndexedURL(3))) != NULL); + ASSERT_TRUE(AddFolder(1, folder1, 3, IndexedSubfolderName(5)) != NULL); + ASSERT_TRUE(AddURL( + 1, folder1, 4, IndexedURLTitle(1), GURL(IndexedURL(1))) != NULL); + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3711273 - Merge disjoint sets of bookmark hierarchy under bookmark +// folder. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_Merge_SimpleBMHierarchy_DisjointSets_Under_BMFolder) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + const BookmarkNode* folder0 = + AddFolder(0, 0, kGenericFolderName); + ASSERT_TRUE(folder0 != NULL); + ASSERT_TRUE(AddURL( + 0, folder0, 0, IndexedURLTitle(1), GURL(IndexedURL(1))) != NULL); + ASSERT_TRUE(AddFolder(0, folder0, 1, IndexedSubfolderName(2)) != NULL); + ASSERT_TRUE(AddURL( + 0, folder0, 2, IndexedURLTitle(3), GURL(IndexedURL(3))) != NULL); + ASSERT_TRUE(AddFolder(0, folder0, 3, IndexedSubfolderName(4)) != NULL); + + const BookmarkNode* folder1 = AddFolder(1, 0, kGenericFolderName); + ASSERT_TRUE(folder1 != NULL); + ASSERT_TRUE(AddFolder(1, folder1, 0, IndexedSubfolderName(5)) != NULL); + ASSERT_TRUE(AddFolder(1, folder1, 1, IndexedSubfolderName(6)) != NULL); + ASSERT_TRUE(AddURL( + 1, folder1, 2, IndexedURLTitle(7), GURL(IndexedURL(7))) != NULL); + ASSERT_TRUE(AddURL( + 1, folder1, 3, IndexedURLTitle(8), GURL(IndexedURL(8))) != NULL); + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3639296 - Merge disjoint sets of bookmark hierarchy under bookmark +// bar. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_Merge_SimpleBMHierarchy_DisjointSets_Under_BookmarkBar) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i+1); + GURL url = GURL(IndexedURL(i+1)); + ASSERT_TRUE(AddURL(0, i, title, url) != NULL); + } + + for (int j = 0; j < 3; ++j) { + std::wstring title = IndexedURLTitle(j+4); + GURL url = GURL(IndexedURL(j+4)); + ASSERT_TRUE(AddURL(0, j, title, url) != NULL); + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3616282 - Merge sets of duplicate bookmarks under bookmark bar. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_Merge_SimpleBMHierarchy_DuplicateBMs_Under_BMBar) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + // Let's add duplicate set of bookmark {1,2,2,3,3,3,4,4,4,4} to client0. + int node_index = 0; + for (int i = 1; i < 5 ; ++i) { + for (int j = 0; j < i; ++j) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, node_index, title, url) != NULL); + ++node_index; + } + } + // Let's add a set of bookmarks {1,2,3,4} to client1. + for (int i = 0; i < 4; ++i) { + std::wstring title = IndexedURLTitle(i+1); + GURL url = GURL(IndexedURL(i+1)); + ASSERT_TRUE(AddURL(1, i, title, url) != NULL); + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + + for (int i = 1; i < 5 ; ++i) { + ASSERT_TRUE(CountBookmarksWithTitlesMatching(1, IndexedURLTitle(i)) == i); + } +} + +// TCM ID - 6593872. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, DisableBookmarks) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForDatatype(syncable::BOOKMARKS)); + ASSERT_TRUE(AddFolder(1, kGenericFolderName) != NULL); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_FALSE(AllModelsMatch()); + + ASSERT_TRUE(GetClient(1)->EnableSyncForDatatype(syncable::BOOKMARKS)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); +} + +// TCM ID - 7343544. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, DisableSync) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForAllDatatypes()); + ASSERT_TRUE(AddFolder(0, IndexedFolderName(0)) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Added a folder.")); + ASSERT_FALSE(AllModelsMatch()); + + ASSERT_TRUE(AddFolder(1, IndexedFolderName(1)) != NULL); + ASSERT_FALSE(AllModelsMatch()); + + ASSERT_TRUE(GetClient(1)->EnableSyncForAllDatatypes()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); +} + +// TCM ID - 3662298 - Test adding duplicate folder - Both with different BMs +// underneath. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, MC_DuplicateFolders) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + const BookmarkNode* folder0 = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder0 != NULL); + const BookmarkNode* folder1 = AddFolder(1, kGenericFolderName); + ASSERT_TRUE(folder1 != NULL); + for (int i = 0; i < 5; ++i) { + std::wstring title0 = IndexedURLTitle(i); + GURL url0 = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder0, i, title0, url0) != NULL); + std::wstring title1 = IndexedURLTitle(i+5); + GURL url1 = GURL(IndexedURL(i+5)); + ASSERT_TRUE(AddURL(1, folder1, i, title1, url1) != NULL); + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3719307 - Test a scenario of updating the name of the same bookmark +// from two clients at the same time. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_BookmarkNameChangeConflict) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + const BookmarkNode* folder0 = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder0 != NULL); + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder0, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); + + DisableVerifier(); + GURL url(IndexedURL(0)); + SetTitle(0, GetUniqueNodeByURL(0, url), L"Title++"); + SetTitle(1, GetUniqueNodeByURL(1, url), L"Title--"); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3672299 - Test a scenario of updating the URL of the same bookmark +// from two clients at the same time. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_BookmarkURLChangeConflict) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + const BookmarkNode* folder0 = AddFolder(0, kGenericFolderName); + ASSERT_TRUE(folder0 != NULL); + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folder0, i, title, url) != NULL); + } + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); + + DisableVerifier(); + GURL url(IndexedURL(0)); + ASSERT_TRUE(SetURL( + 0, GetUniqueNodeByURL(0, url), GURL("http://www.google.com/00"))); + ASSERT_TRUE(SetURL( + 1, GetUniqueNodeByURL(1, url), GURL("http://www.google.com/11"))); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +// TCM ID - 3699290 - Test a scenario of updating the BM Folder name from two +// clients at the same time. +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + MC_FolderNameChangeConflict) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + DisableVerifier(); + + const BookmarkNode* folderA[2]; + const BookmarkNode* folderB[2]; + const BookmarkNode* folderC[2]; + + // Create empty folder A on both clients. + folderA[0] = AddFolder(0, IndexedFolderName(0)); + ASSERT_TRUE(folderA[0] != NULL); + folderA[1] = AddFolder(1, IndexedFolderName(0)); + ASSERT_TRUE(folderA[1] != NULL); + + // Create folder B with bookmarks on both clients. + folderB[0] = AddFolder(0, IndexedFolderName(1)); + ASSERT_TRUE(folderB[0] != NULL); + folderB[1] = AddFolder(1, IndexedFolderName(1)); + ASSERT_TRUE(folderB[1] != NULL); + for (int i = 0; i < 3; ++i) { + std::wstring title = IndexedURLTitle(i); + GURL url = GURL(IndexedURL(i)); + ASSERT_TRUE(AddURL(0, folderB[0], i, title, url) != NULL); + } + + // Create folder C with bookmarks and subfolders on both clients. + folderC[0] = AddFolder(0, IndexedFolderName(2)); + ASSERT_TRUE(folderC[0] != NULL); + folderC[1] = AddFolder(1, IndexedFolderName(2)); + ASSERT_TRUE(folderC[1] != NULL); + for (int i = 0; i < 3; ++i) { + std::wstring folder_name = IndexedSubfolderName(i); + const BookmarkNode* subfolder = AddFolder(0, folderC[0], i, folder_name); + ASSERT_TRUE(subfolder != NULL); + for (int j = 0; j < 3; ++j) { + std::wstring title = IndexedURLTitle(j); + GURL url = GURL(IndexedURL(j)); + ASSERT_TRUE(AddURL(0, subfolder, j, title, url) != NULL); + } + } + + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); + + // Simultaneously rename folder A on both clients. + SetTitle(0, folderA[0], L"Folder A++"); + SetTitle(1, folderA[1], L"Folder A--"); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); + + // Simultaneously rename folder B on both clients. + SetTitle(0, folderB[0], L"Folder B++"); + SetTitle(1, folderB[1], L"Folder B--"); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); + + // Simultaneously rename folder C on both clients. + SetTitle(0, folderC[0], L"Folder C++"); + SetTitle(1, folderC[1], L"Folder C--"); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatch()); + ASSERT_FALSE(ContainsDuplicateBookmarks(0)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SingleClientEnabledEncryption) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(EnableEncryption(0, syncable::BOOKMARKS)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IsEncrypted(0, syncable::BOOKMARKS)); + ASSERT_TRUE(IsEncrypted(1, syncable::BOOKMARKS)); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SingleClientEnabledEncryptionAndChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(EnableEncryption(0, syncable::BOOKMARKS)); + ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IsEncrypted(0, syncable::BOOKMARKS)); + ASSERT_TRUE(IsEncrypted(1, syncable::BOOKMARKS)); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + BothClientsEnabledEncryption) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(EnableEncryption(0, syncable::BOOKMARKS)); + ASSERT_TRUE(EnableEncryption(1, syncable::BOOKMARKS)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(IsEncrypted(0, syncable::BOOKMARKS)); + ASSERT_TRUE(IsEncrypted(1, syncable::BOOKMARKS)); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SingleClientEnabledEncryptionBothChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(EnableEncryption(0, syncable::BOOKMARKS)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(IsEncrypted(0, syncable::BOOKMARKS)); + ASSERT_TRUE(IsEncrypted(1, syncable::BOOKMARKS)); + ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))) != NULL); + ASSERT_TRUE(AddURL(0, IndexedURLTitle(1), GURL(IndexedURL(1))) != NULL); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllModelsMatchVerifier()); + ASSERT_TRUE(IsEncrypted(0, syncable::BOOKMARKS)); + ASSERT_TRUE(IsEncrypted(1, syncable::BOOKMARKS)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, + SingleClientEnabledEncryptionAndChangedMultipleTimes) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(0, IndexedURLTitle(0), GURL(IndexedURL(0))) != NULL); + ASSERT_TRUE(EnableEncryption(0, syncable::BOOKMARKS)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IsEncrypted(0, syncable::BOOKMARKS)); + ASSERT_TRUE(IsEncrypted(1, syncable::BOOKMARKS)); + ASSERT_TRUE(AllModelsMatchVerifier()); + + ASSERT_TRUE(AddURL(0, IndexedURLTitle(1), GURL(IndexedURL(1))) != NULL); + ASSERT_TRUE(AddFolder(0, IndexedFolderName(0)) != NULL); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllModelsMatchVerifier()); +} + +// TODO(zea): Add first time sync functionality testing. In particular, when +// there are encrypted types in first time sync we need to ensure we don't +// duplicate bookmarks. diff --git a/chrome/browser/sync/test/live_sync/two_client_extensions_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_extensions_sync_test.cc new file mode 100644 index 0000000..379370d --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_extensions_sync_test.cc @@ -0,0 +1,283 @@ +// Copyright (c) 2011 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/basictypes.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/extensions_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using extensions_helper::AllProfilesHaveSameExtensionsAsVerifier; +using extensions_helper::DisableExtension; +using extensions_helper::EnableExtension; +using extensions_helper::HasSameExtensionsAsVerifier; +using extensions_helper::IncognitoDisableExtension; +using extensions_helper::IncognitoEnableExtension; +using extensions_helper::InstallExtension; +using extensions_helper::InstallExtensionsPendingForSync; +using extensions_helper::UninstallExtension; + +class TwoClientExtensionsSyncTest : public LiveSyncTest { + public: + TwoClientExtensionsSyncTest() : LiveSyncTest(TWO_CLIENT) {} + + virtual ~TwoClientExtensionsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientExtensionsSyncTest); +}; + +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, StartWithNoExtensions) { + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, StartWithSameExtensions) { + ASSERT_TRUE(SetupClients()); + + const int kNumExtensions = 5; + for (int i = 0; i < kNumExtensions; ++i) { + InstallExtension(GetProfile(0), i); + InstallExtension(GetProfile(1), i); + InstallExtension(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, + StartWithDifferentExtensions) { + ASSERT_TRUE(SetupClients()); + + int i = 0; + + const int kNumCommonExtensions = 5; + for (int j = 0; j < kNumCommonExtensions; ++i, ++j) { + InstallExtension(GetProfile(0), i); + InstallExtension(GetProfile(1), i); + InstallExtension(verifier(), i); + } + + const int kNumProfile0Extensions = 10; + for (int j = 0; j < kNumProfile0Extensions; ++i, ++j) { + InstallExtension(GetProfile(0), i); + InstallExtension(verifier(), i); + } + + const int kNumProfile1Extensions = 10; + for (int j = 0; j < kNumProfile1Extensions; ++i, ++j) { + InstallExtension(GetProfile(1), i); + InstallExtension(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AwaitQuiescence()); + + InstallExtensionsPendingForSync(GetProfile(0)); + InstallExtensionsPendingForSync(GetProfile(1)); + + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, + InstallDifferentExtensions) { + ASSERT_TRUE(SetupClients()); + + int i = 0; + + const int kNumCommonExtensions = 5; + for (int j = 0; j < kNumCommonExtensions; ++i, ++j) { + InstallExtension(GetProfile(0), i); + InstallExtension(GetProfile(1), i); + InstallExtension(verifier(), i); + } + + ASSERT_TRUE(SetupSync()); + + ASSERT_TRUE(AwaitQuiescence()); + + const int kNumProfile0Extensions = 10; + for (int j = 0; j < kNumProfile0Extensions; ++i, ++j) { + InstallExtension(GetProfile(0), i); + InstallExtension(verifier(), i); + } + + const int kNumProfile1Extensions = 10; + for (int j = 0; j < kNumProfile1Extensions; ++i, ++j) { + InstallExtension(GetProfile(1), i); + InstallExtension(verifier(), i); + } + + ASSERT_TRUE(AwaitQuiescence()); + + InstallExtensionsPendingForSync(GetProfile(0)); + InstallExtensionsPendingForSync(GetProfile(1)); + + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TCM ID - 3637311. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, Add) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + InstallExtension(GetProfile(0), 0); + InstallExtension(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + + InstallExtensionsPendingForSync(GetProfile(0)); + InstallExtensionsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TCM ID - 3724281. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, Uninstall) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + InstallExtension(GetProfile(0), 0); + InstallExtension(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + + InstallExtensionsPendingForSync(GetProfile(0)); + InstallExtensionsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + UninstallExtension(GetProfile(0), 0); + UninstallExtension(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TCM ID - 3635304. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, Merge) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + InstallExtension(GetProfile(0), 0); + InstallExtension(GetProfile(1), 0); + ASSERT_TRUE(AwaitQuiescence()); + + UninstallExtension(GetProfile(0), 0); + InstallExtension(GetProfile(0), 1); + InstallExtension(verifier(), 1); + + InstallExtension(GetProfile(0), 2); + InstallExtension(GetProfile(1), 2); + InstallExtension(verifier(), 2); + + InstallExtension(GetProfile(1), 3); + InstallExtension(verifier(), 3); + + ASSERT_TRUE(AwaitQuiescence()); + InstallExtensionsPendingForSync(GetProfile(0)); + InstallExtensionsPendingForSync(GetProfile(1)); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TCM ID - 3605300. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, + UpdateEnableDisableExtension) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + InstallExtension(GetProfile(0), 0); + InstallExtension(GetProfile(1), 0); + InstallExtension(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + DisableExtension(GetProfile(0), 0); + DisableExtension(verifier(), 0); + ASSERT_TRUE(HasSameExtensionsAsVerifier(0)); + ASSERT_FALSE(HasSameExtensionsAsVerifier(1)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + EnableExtension(GetProfile(1), 0); + EnableExtension(verifier(), 0); + ASSERT_TRUE(HasSameExtensionsAsVerifier(1)); + ASSERT_FALSE(HasSameExtensionsAsVerifier(0)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TCM ID - 3728322. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, + UpdateIncognitoEnableDisable) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + InstallExtension(GetProfile(0), 0); + InstallExtension(GetProfile(1), 0); + InstallExtension(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + IncognitoEnableExtension(GetProfile(0), 0); + IncognitoEnableExtension(verifier(), 0); + ASSERT_TRUE(HasSameExtensionsAsVerifier(0)); + ASSERT_FALSE(HasSameExtensionsAsVerifier(1)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + IncognitoDisableExtension(GetProfile(1), 0); + IncognitoDisableExtension(verifier(), 0); + ASSERT_TRUE(HasSameExtensionsAsVerifier(1)); + ASSERT_FALSE(HasSameExtensionsAsVerifier(0)); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TCM ID - 3732278. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, DisableExtensions) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForDatatype(syncable::EXTENSIONS)); + InstallExtension(GetProfile(0), 1); + InstallExtension(verifier(), 1); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_FALSE(AllProfilesHaveSameExtensionsAsVerifier()); + + ASSERT_TRUE(GetClient(1)->EnableSyncForDatatype(syncable::EXTENSIONS)); + ASSERT_TRUE(AwaitQuiescence()); + InstallExtensionsPendingForSync(GetProfile(0)); + InstallExtensionsPendingForSync(GetProfile(1)); + InstallExtensionsPendingForSync(verifier()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TCM ID - 3606290. +IN_PROC_BROWSER_TEST_F(TwoClientExtensionsSyncTest, DisableSync) { + ASSERT_TRUE(SetupSync()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForAllDatatypes()); + InstallExtension(GetProfile(0), 0); + InstallExtension(verifier(), 0); + ASSERT_TRUE( + GetClient(0)->AwaitSyncCycleCompletion("Installed an extension.")); + ASSERT_TRUE(HasSameExtensionsAsVerifier(0)); + ASSERT_FALSE(HasSameExtensionsAsVerifier(1)); + + ASSERT_TRUE(GetClient(1)->EnableSyncForAllDatatypes()); + ASSERT_TRUE(AwaitQuiescence()); + InstallExtensionsPendingForSync(GetProfile(0)); + InstallExtensionsPendingForSync(GetProfile(1)); + InstallExtensionsPendingForSync(verifier()); + ASSERT_TRUE(AllProfilesHaveSameExtensionsAsVerifier()); +} + +// TODO(akalin): Add tests exercising: +// - Offline installation/uninstallation behavior diff --git a/chrome/browser/sync/test/live_sync/two_client_passwords_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_passwords_sync_test.cc new file mode 100644 index 0000000..7916fa6 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_passwords_sync_test.cc @@ -0,0 +1,323 @@ +// Copyright (c) 2011 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/utf_string_conversions.h" +#include "chrome/browser/sync/engine/model_safe_worker.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/sessions/session_state.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/passwords_helper.h" + +using passwords_helper::AddLogin; +using passwords_helper::AllProfilesContainSamePasswordForms; +using passwords_helper::AllProfilesContainSamePasswordFormsAsVerifier; +using passwords_helper::CreateTestPasswordForm; +using passwords_helper::GetPasswordCount; +using passwords_helper::GetPasswordStore; +using passwords_helper::GetVerifierPasswordCount; +using passwords_helper::GetVerifierPasswordStore; +using passwords_helper::ProfileContainsSamePasswordFormsAsVerifier; +using passwords_helper::RemoveLogin; +using passwords_helper::RemoveLogins; +using passwords_helper::SetPassphrase; +using passwords_helper::UpdateLogin; + +using webkit_glue::PasswordForm; + +static const char* kValidPassphrase = "passphrase!"; + +class TwoClientPasswordsSyncTest : public LiveSyncTest { + public: + TwoClientPasswordsSyncTest() : LiveSyncTest(TWO_CLIENT) {} + virtual ~TwoClientPasswordsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientPasswordsSyncTest); +}; + +// TCM ID - 3732277 +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_Add) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, Add) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + + PasswordForm form = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form); + ASSERT_EQ(1, GetVerifierPasswordCount()); + AddLogin(GetPasswordStore(0), form); + ASSERT_EQ(1, GetPasswordCount(0)); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); +} + +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_Race) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, Race) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordForms()); + + PasswordForm form0 = CreateTestPasswordForm(0); + AddLogin(GetPasswordStore(0), form0); + + PasswordForm form1 = form0; + form1.password_value = ASCIIToUTF16("password1"); + AddLogin(GetPasswordStore(1), form1); + + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesContainSamePasswordForms()); +} + +// TCM ID - 4577932. +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_DisablePasswords) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DisablePasswords) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForDatatype(syncable::PASSWORDS)); + PasswordForm form = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form); + ASSERT_EQ(1, GetVerifierPasswordCount()); + AddLogin(GetPasswordStore(0), form); + ASSERT_EQ(1, GetPasswordCount(0)); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(ProfileContainsSamePasswordFormsAsVerifier(0)); + ASSERT_FALSE(ProfileContainsSamePasswordFormsAsVerifier(1)); + + ASSERT_TRUE(GetClient(1)->EnableSyncForDatatype(syncable::PASSWORDS)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + ASSERT_EQ(1, GetPasswordCount(1)); +} + +// TCM ID - 4649281. +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_DisableSync) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DisableSync) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + + ASSERT_TRUE(GetClient(1)->DisableSyncForAllDatatypes()); + PasswordForm form = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form); + ASSERT_EQ(1, GetVerifierPasswordCount()); + AddLogin(GetPasswordStore(0), form); + ASSERT_EQ(1, GetPasswordCount(0)); + + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Added a password.")); + ASSERT_TRUE(ProfileContainsSamePasswordFormsAsVerifier(0)); + ASSERT_FALSE(ProfileContainsSamePasswordFormsAsVerifier(1)); + + ASSERT_TRUE(GetClient(1)->EnableSyncForAllDatatypes()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + ASSERT_EQ(1, GetPasswordCount(1)); +} + +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_SetPassphrase) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, SetPassphrase) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + SetPassphrase(0, kValidPassphrase, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + SetPassphrase(1, kValidPassphrase, false); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->AwaitSyncCycleCompletion("Set passphrase.")); +} + +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, + DISABLED_SetPassphraseAndAddPassword) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, + SetPassphraseAndAddPassword) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + SetPassphrase(0, kValidPassphrase, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + SetPassphrase(1, kValidPassphrase, false); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + + PasswordForm form = CreateTestPasswordForm(0); + AddLogin(GetPasswordStore(0), form); + ASSERT_EQ(1, GetPasswordCount(0)); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_EQ(1, GetPasswordCount(1)); +} + +// TCM ID - 4603879 +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_Update) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, Update) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + + PasswordForm form = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form); + AddLogin(GetPasswordStore(0), form); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + form.password_value = ASCIIToUTF16("updated"); + UpdateLogin(GetVerifierPasswordStore(), form); + UpdateLogin(GetPasswordStore(1), form); + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(1, GetVerifierPasswordCount()); + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); +} + +// TCM ID - 3719309 +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_Delete) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, Delete) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + + PasswordForm form0 = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form0); + AddLogin(GetPasswordStore(0), form0); + PasswordForm form1 = CreateTestPasswordForm(1); + AddLogin(GetVerifierPasswordStore(), form1); + AddLogin(GetPasswordStore(0), form1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + RemoveLogin(GetPasswordStore(1), form0); + RemoveLogin(GetVerifierPasswordStore(), form0); + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(1, GetVerifierPasswordCount()); + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); +} + +// TCM ID - 7573511 +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_DeleteAll) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DeleteAll) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + + PasswordForm form0 = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form0); + AddLogin(GetPasswordStore(0), form0); + PasswordForm form1 = CreateTestPasswordForm(1); + AddLogin(GetVerifierPasswordStore(), form1); + AddLogin(GetPasswordStore(0), form1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + RemoveLogins(GetPasswordStore(1)); + RemoveLogins(GetVerifierPasswordStore()); + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(0, GetVerifierPasswordCount()); + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); +} + +// TCM ID - 3694311 +// http://crbug.com/90460 +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, DISABLED_Merge) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); + + PasswordForm form0 = CreateTestPasswordForm(0); + AddLogin(GetVerifierPasswordStore(), form0); + AddLogin(GetPasswordStore(0), form0); + PasswordForm form1 = CreateTestPasswordForm(1); + AddLogin(GetVerifierPasswordStore(), form1); + AddLogin(GetPasswordStore(0), form1); + AddLogin(GetPasswordStore(1), form1); + PasswordForm form2 = CreateTestPasswordForm(2); + AddLogin(GetVerifierPasswordStore(), form2); + AddLogin(GetPasswordStore(1), form2); + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(3, GetVerifierPasswordCount()); + ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier()); +} + +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, + DISABLED_SetPassphraseAndThenSetupSync) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, + SetPassphraseAndThenSetupSync) { +#endif + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + + ASSERT_TRUE(GetClient(0)->SetupSync()); + SetPassphrase(0, kValidPassphrase, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Initial sync.")); + + ASSERT_FALSE(GetClient(1)->SetupSync()); + SetPassphrase(1, kValidPassphrase, false); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->AwaitSyncCycleCompletion("Initial sync.")); + + // Following ensures types are enabled and active (see bug 87572). + browser_sync::ModelSafeRoutingInfo routes; + GetClient(0)->service()->GetModelSafeRoutingInfo(&routes); + ASSERT_EQ(browser_sync::GROUP_PASSWORD, routes[syncable::PASSWORDS]); + routes.clear(); + GetClient(1)->service()->GetModelSafeRoutingInfo(&routes); + ASSERT_EQ(browser_sync::GROUP_PASSWORD, routes[syncable::PASSWORDS]); +} + +// TODO(sync): Enable after MockKeychain is fixed. http://crbug.com/89808. +#if defined(OS_MACOSX) +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, + DISABLED_SetPassphraseTwice) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, + SetPassphraseTwice) { +#endif + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + SetPassphrase(0, kValidPassphrase, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + SetPassphrase(1, kValidPassphrase, false); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->AwaitSyncCycleCompletion("Set passphrase.")); + + SetPassphrase(1, kValidPassphrase, false); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->AwaitSyncCycleCompletion("Set passphrase again.")); +} diff --git a/chrome/browser/sync/test/live_sync/two_client_preferences_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_preferences_sync_test.cc new file mode 100644 index 0000000..60ef890 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_preferences_sync_test.cc @@ -0,0 +1,669 @@ +// Copyright (c) 2011 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/values.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/translate/translate_prefs.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/preferences_helper.h" +#include "chrome/common/pref_names.h" + +using preferences_helper::AppendStringPref; +using preferences_helper::BooleanPrefMatches; +using preferences_helper::ChangeBooleanPref; +using preferences_helper::ChangeIntegerPref; +using preferences_helper::ChangeListPref; +using preferences_helper::ChangeStringPref; +using preferences_helper::GetPrefs; +using preferences_helper::IntegerPrefMatches; +using preferences_helper::ListPrefMatches; +using preferences_helper::StringPrefMatches; + +class TwoClientPreferencesSyncTest : public LiveSyncTest { + public: + TwoClientPreferencesSyncTest() : LiveSyncTest(TWO_CLIENT) {} + virtual ~TwoClientPreferencesSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientPreferencesSyncTest); +}; + +// TCM ID - 7306186. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kHomePageIsNewTabPage) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); + + ChangeBooleanPref(0, prefs::kHomePageIsNewTabPage); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); +} + +// TCM ID - 7260488. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, Race) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(StringPrefMatches(prefs::kHomePage)); + + ChangeStringPref(0, prefs::kHomePage, + "http://www.google.com/0"); + ChangeStringPref(1, prefs::kHomePage, + "http://www.google.com/1"); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(StringPrefMatches(prefs::kHomePage)); +} + +// TCM ID - 3649278. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kPasswordManagerEnabled) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); + + ChangeBooleanPref(0, prefs::kPasswordManagerEnabled); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); +} + +// TCM ID - 3699293. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kKeepEverythingSynced) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches( + prefs::kKeepEverythingSynced)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncThemes)); + + GetClient(0)->DisableSyncForDatatype(syncable::THEMES); + ASSERT_FALSE(BooleanPrefMatches( + prefs::kKeepEverythingSynced)); +} + +// TCM ID - 3661290. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, DisablePreferences) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncPreferences)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); + + GetClient(1)->DisableSyncForDatatype(syncable::PREFERENCES); + ChangeBooleanPref(0, prefs::kPasswordManagerEnabled); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_FALSE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); + + GetClient(1)->EnableSyncForDatatype(syncable::PREFERENCES); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); +} + +// TCM ID - 3664292. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, DisableSync) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncPreferences)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); + + GetClient(1)->DisableSyncForAllDatatypes(); + ChangeBooleanPref(0, prefs::kPasswordManagerEnabled); + ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion("Changed a preference.")); + ASSERT_FALSE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); + + ChangeBooleanPref(1, prefs::kShowHomeButton); + ASSERT_FALSE(BooleanPrefMatches(prefs::kShowHomeButton)); + + GetClient(1)->EnableSyncForAllDatatypes(); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kPasswordManagerEnabled)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); +} + +// TCM ID - 3604297. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, SignInDialog) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncPreferences)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncBookmarks)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncThemes)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncExtensions)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kSyncAutofill)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kKeepEverythingSynced)); + + GetClient(0)->DisableSyncForDatatype(syncable::PREFERENCES); + GetClient(1)->EnableSyncForDatatype(syncable::PREFERENCES); + GetClient(0)->DisableSyncForDatatype(syncable::AUTOFILL); + GetClient(1)->EnableSyncForDatatype(syncable::AUTOFILL); + GetClient(0)->DisableSyncForDatatype(syncable::BOOKMARKS); + GetClient(1)->EnableSyncForDatatype(syncable::BOOKMARKS); + GetClient(0)->DisableSyncForDatatype(syncable::EXTENSIONS); + GetClient(1)->EnableSyncForDatatype(syncable::EXTENSIONS); + GetClient(0)->DisableSyncForDatatype(syncable::THEMES); + GetClient(1)->EnableSyncForDatatype(syncable::THEMES); + + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_FALSE(BooleanPrefMatches(prefs::kSyncPreferences)); + ASSERT_FALSE(BooleanPrefMatches(prefs::kSyncBookmarks)); + ASSERT_FALSE(BooleanPrefMatches(prefs::kSyncThemes)); + ASSERT_FALSE(BooleanPrefMatches(prefs::kSyncExtensions)); + ASSERT_FALSE(BooleanPrefMatches(prefs::kSyncAutofill)); + ASSERT_FALSE(BooleanPrefMatches( + prefs::kKeepEverythingSynced)); +} + +// TCM ID - 3666296. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kShowBookmarkBar) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowBookmarkBar)); + + ChangeBooleanPref(0, prefs::kShowBookmarkBar); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowBookmarkBar)); +} + +// TCM ID - 3611311. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kCheckDefaultBrowser) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches( + prefs::kCheckDefaultBrowser)); + + ChangeBooleanPref(0, prefs::kCheckDefaultBrowser); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_FALSE(BooleanPrefMatches( + prefs::kCheckDefaultBrowser)); +} + +// TCM ID - 3628298. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kHomePage) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(StringPrefMatches(prefs::kHomePage)); + + ChangeStringPref(0, prefs::kHomePage, + "http://news.google.com"); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(StringPrefMatches(prefs::kHomePage)); +} + +// TCM ID - 7297269. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kShowHomeButton) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); + + ChangeBooleanPref(0, prefs::kShowHomeButton); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); +} + +// TCM ID - 3710285. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kEnableTranslate) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableTranslate)); + + ChangeBooleanPref(0, prefs::kEnableTranslate); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableTranslate)); +} + +// TCM ID - 3664293. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kAutofillEnabled) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kAutofillEnabled)); + + ChangeBooleanPref(0, prefs::kAutofillEnabled); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kAutofillEnabled)); +} + +// TCM ID - 3632259. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kURLsToRestoreOnStartup) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(IntegerPrefMatches(prefs::kRestoreOnStartup)); + ASSERT_TRUE(ListPrefMatches( + prefs::kURLsToRestoreOnStartup)); + + ChangeIntegerPref(0, prefs::kRestoreOnStartup, 0); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IntegerPrefMatches(prefs::kRestoreOnStartup)); + + ListValue urls; + urls.Append(Value::CreateStringValue("http://www.google.com/")); + urls.Append(Value::CreateStringValue("http://www.flickr.com/")); + ChangeIntegerPref(0, prefs::kRestoreOnStartup, 4); + ChangeListPref(0, prefs::kURLsToRestoreOnStartup, urls); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IntegerPrefMatches(prefs::kRestoreOnStartup)); + ASSERT_TRUE(ListPrefMatches( + prefs::kURLsToRestoreOnStartup)); +} + +// TCM ID - 3684287. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kRestoreOnStartup) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(IntegerPrefMatches(prefs::kRestoreOnStartup)); + + ChangeIntegerPref(0, prefs::kRestoreOnStartup, 1); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IntegerPrefMatches(prefs::kRestoreOnStartup)); +} + +// TCM ID - 3703314. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, Privacy) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches( + prefs::kAlternateErrorPagesEnabled)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kSearchSuggestEnabled)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kNetworkPredictionEnabled)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kSafeBrowsingEnabled)); + + ChangeBooleanPref(0, prefs::kAlternateErrorPagesEnabled); + ChangeBooleanPref(0, prefs::kSearchSuggestEnabled); + ChangeBooleanPref(0, prefs::kNetworkPredictionEnabled); + ChangeBooleanPref(0, prefs::kSafeBrowsingEnabled); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kAlternateErrorPagesEnabled)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kSearchSuggestEnabled)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kNetworkPredictionEnabled)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kSafeBrowsingEnabled)); +} + +// TCM ID - 3649279. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, ClearData) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches( + prefs::kDeleteBrowsingHistory)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kDeleteDownloadHistory)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeleteCache)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeleteCookies)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeletePasswords)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeleteFormData)); + + ChangeBooleanPref(0, prefs::kDeleteBrowsingHistory); + ChangeBooleanPref(0, prefs::kDeleteDownloadHistory); + ChangeBooleanPref(0, prefs::kDeleteCache); + ChangeBooleanPref(0, prefs::kDeleteCookies); + ChangeBooleanPref(0, prefs::kDeletePasswords); + ChangeBooleanPref(0, prefs::kDeleteFormData); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kDeleteBrowsingHistory)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kDeleteDownloadHistory)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeleteCache)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeleteCookies)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeletePasswords)); + ASSERT_TRUE(BooleanPrefMatches(prefs::kDeleteFormData)); +} + +// TCM ID - 3686300. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kWebKitUsesUniversalDetector) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kWebKitUsesUniversalDetector)); + + ChangeBooleanPref(0, prefs::kWebKitUsesUniversalDetector); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kWebKitUsesUniversalDetector)); +} + +// TCM ID - 3673298. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kDefaultCharset) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(StringPrefMatches(prefs::kDefaultCharset)); + + ChangeStringPref(0, prefs::kDefaultCharset, "Thai"); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(StringPrefMatches(prefs::kDefaultCharset)); +} + +// TCM ID - 3653296. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kBlockThirdPartyCookies) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kBlockThirdPartyCookies)); + + ChangeBooleanPref(0, prefs::kBlockThirdPartyCookies); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kBlockThirdPartyCookies)); +} + +// TCM ID - 7297279. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kClearSiteDataOnExit) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kClearSiteDataOnExit)); + + ChangeBooleanPref(0, prefs::kClearSiteDataOnExit); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kClearSiteDataOnExit)); +} + +// TCM ID - 7306184. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kSafeBrowsingEnabled) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kSafeBrowsingEnabled)); + + ChangeBooleanPref(0, prefs::kSafeBrowsingEnabled); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kSafeBrowsingEnabled)); +} + +// TCM ID - 3624302. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kAutofillAuxiliaryProfilesEnabled) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + + ASSERT_TRUE(BooleanPrefMatches( + prefs::kAutofillAuxiliaryProfilesEnabled)); + + ChangeBooleanPref(0, + prefs::kAutofillAuxiliaryProfilesEnabled); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // kAutofillAuxiliaryProfilesEnabled is only synced on Mac. +#if defined(OS_MACOSX) + ASSERT_TRUE(BooleanPrefMatches( + prefs::kAutofillAuxiliaryProfilesEnabled)); +#else + ASSERT_FALSE(BooleanPrefMatches( + prefs::kAutofillAuxiliaryProfilesEnabled)); +#endif // OS_MACOSX +} + +// TCM ID - 3717298. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kPromptForDownload) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kPromptForDownload)); + + ChangeBooleanPref(0, prefs::kPromptForDownload); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kPromptForDownload)); +} + +// TCM ID - 3729263. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kPrefTranslateLanguageBlacklist) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableTranslate)); + + TranslatePrefs translate_client0_prefs(GetPrefs(0)); + TranslatePrefs translate_client1_prefs(GetPrefs(1)); + ASSERT_FALSE(translate_client0_prefs.IsLanguageBlacklisted("fr")); + translate_client0_prefs.BlacklistLanguage("fr"); + ASSERT_TRUE(translate_client0_prefs.IsLanguageBlacklisted("fr")); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(translate_client1_prefs.IsLanguageBlacklisted("fr")); + + translate_client0_prefs.RemoveLanguageFromBlacklist("fr"); + ASSERT_FALSE(translate_client0_prefs.IsLanguageBlacklisted("fr")); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_FALSE(translate_client1_prefs.IsLanguageBlacklisted("fr")); +} + +// TCM ID - 7307195. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kPrefTranslateWhitelists) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableTranslate)); + + TranslatePrefs translate_client0_prefs(GetPrefs(0)); + TranslatePrefs translate_client1_prefs(GetPrefs(1)); + ASSERT_FALSE(translate_client0_prefs.IsLanguagePairWhitelisted("en", "bg")); + translate_client0_prefs.WhitelistLanguagePair("en", "bg"); + ASSERT_TRUE(translate_client0_prefs.IsLanguagePairWhitelisted("en", "bg")); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(translate_client1_prefs.IsLanguagePairWhitelisted("en", "bg")); + + translate_client0_prefs.RemoveLanguagePairFromWhitelist("en", "bg"); + ASSERT_FALSE(translate_client0_prefs.IsLanguagePairWhitelisted("en", "bg")); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_FALSE(translate_client1_prefs.IsLanguagePairWhitelisted("en", "bg")); +} + +// TCM ID - 3625298. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kPrefTranslateSiteBlacklist) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableTranslate)); + + GURL url("http://www.google.com"); + std::string host(url.host()); + TranslatePrefs translate_client0_prefs(GetPrefs(0)); + TranslatePrefs translate_client1_prefs(GetPrefs(1)); + ASSERT_FALSE(translate_client0_prefs.IsSiteBlacklisted(host)); + translate_client0_prefs.BlacklistSite(host); + ASSERT_TRUE(translate_client0_prefs.IsSiteBlacklisted(host)); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(translate_client1_prefs.IsSiteBlacklisted(host)); + + translate_client0_prefs.RemoveSiteFromBlacklist(host); + ASSERT_FALSE(translate_client0_prefs.IsSiteBlacklisted(host)); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_FALSE(translate_client1_prefs.IsSiteBlacklisted(host)); +} + +// TCM ID - 6515252. +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kExtensionsUIDeveloperMode) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kExtensionsUIDeveloperMode)); + + ChangeBooleanPref(0, prefs::kExtensionsUIDeveloperMode); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kExtensionsUIDeveloperMode)); +} + +// TCM ID - 7583816 +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kAcceptLanguages) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + DisableVerifier(); + ASSERT_TRUE(StringPrefMatches(prefs::kAcceptLanguages)); + + AppendStringPref(0, prefs::kAcceptLanguages, ",ar"); + AppendStringPref(1, prefs::kAcceptLanguages, ",fr"); + ASSERT_TRUE(AwaitQuiescence()); + // kAcceptLanguages is not synced on Mac. +#if !defined(OS_MACOSX) + ASSERT_TRUE(StringPrefMatches(prefs::kAcceptLanguages)); +#else + ASSERT_FALSE(StringPrefMatches(prefs::kAcceptLanguages)); +#endif // OS_MACOSX + + ChangeStringPref(0, prefs::kAcceptLanguages, "en-US"); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); +#if !defined(OS_MACOSX) + ASSERT_TRUE(StringPrefMatches(prefs::kAcceptLanguages)); +#else + ASSERT_FALSE(StringPrefMatches(prefs::kAcceptLanguages)); +#endif // OS_MACOSX + + ChangeStringPref(0, prefs::kAcceptLanguages, "ar,en-US"); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); +#if !defined(OS_MACOSX) + ASSERT_TRUE(StringPrefMatches(prefs::kAcceptLanguages)); +#else + ASSERT_FALSE(StringPrefMatches(prefs::kAcceptLanguages)); +#endif // OS_MACOSX +} + +// TCM ID - 7590682 +#if defined(TOOLKIT_USES_GTK) +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kUsesSystemTheme) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kUsesSystemTheme)); + + ChangeBooleanPref(0, prefs::kUsesSystemTheme); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_FALSE(BooleanPrefMatches(prefs::kUsesSystemTheme)); +} +#endif // TOOLKIT_USES_GTK + +// TCM ID - 3636292 +#if defined(TOOLKIT_USES_GTK) +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + kUseCustomChromeFrame) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kUseCustomChromeFrame)); + + ChangeBooleanPref(0, prefs::kUseCustomChromeFrame); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kUseCustomChromeFrame)); +} +#endif // TOOLKIT_USES_GTK + +// TCM ID - 6473347. +#if defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kTapToClickEnabled) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kTapToClickEnabled)); + + ChangeBooleanPref(0, prefs::kTapToClickEnabled); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kTapToClickEnabled)); + + ChangeBooleanPref(1, prefs::kTapToClickEnabled); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kTapToClickEnabled)); +} +#endif // OS_CHROMEOS + +// TCM ID - 6458824. +#if defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, kEnableScreenLock) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableScreenLock)); + + ChangeBooleanPref(0, prefs::kEnableScreenLock); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableScreenLock)); + + ChangeBooleanPref(1, prefs::kEnableScreenLock); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kEnableScreenLock)); +} +#endif // OS_CHROMEOS + +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + SingleClientEnabledEncryption) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(EnableEncryption(0, syncable::PREFERENCES)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IsEncrypted(0, syncable::PREFERENCES)); + ASSERT_TRUE(IsEncrypted(1, syncable::PREFERENCES)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + SingleClientEnabledEncryptionAndChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); + + ChangeBooleanPref(0, prefs::kHomePageIsNewTabPage); + ASSERT_TRUE(EnableEncryption(0, syncable::PREFERENCES)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IsEncrypted(0, syncable::PREFERENCES)); + ASSERT_TRUE(IsEncrypted(1, syncable::PREFERENCES)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + BothClientsEnabledEncryption) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(EnableEncryption(0, syncable::PREFERENCES)); + ASSERT_TRUE(EnableEncryption(1, syncable::PREFERENCES)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(IsEncrypted(0, syncable::PREFERENCES)); + ASSERT_TRUE(IsEncrypted(1, syncable::PREFERENCES)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + SingleClientEnabledEncryptionBothChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); + ASSERT_TRUE(StringPrefMatches(prefs::kHomePage)); + + ASSERT_TRUE(EnableEncryption(0, syncable::PREFERENCES)); + ChangeBooleanPref(0, prefs::kHomePageIsNewTabPage); + ChangeStringPref(1, prefs::kHomePage, + "http://www.google.com/1"); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(IsEncrypted(0, syncable::PREFERENCES)); + ASSERT_TRUE(IsEncrypted(1, syncable::PREFERENCES)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); + ASSERT_TRUE(StringPrefMatches(prefs::kHomePage)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientPreferencesSyncTest, + SingleClientEnabledEncryptionAndChangedMultipleTimes) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); + + ChangeBooleanPref(0, prefs::kHomePageIsNewTabPage); + ASSERT_TRUE(EnableEncryption(0, syncable::PREFERENCES)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IsEncrypted(0, syncable::PREFERENCES)); + ASSERT_TRUE(IsEncrypted(1, syncable::PREFERENCES)); + ASSERT_TRUE(BooleanPrefMatches( + prefs::kHomePageIsNewTabPage)); + + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); + ChangeBooleanPref(0, prefs::kShowHomeButton); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(BooleanPrefMatches(prefs::kShowHomeButton)); +} diff --git a/chrome/browser/sync/test/live_sync/two_client_sessions_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_sessions_sync_test.cc new file mode 100644 index 0000000..b75f06e --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_sessions_sync_test.cc @@ -0,0 +1,353 @@ +// Copyright (c) 2011 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/memory/scoped_vector.h" +#include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/sessions/session_state.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sessions_helper.h" + +using sessions_helper::CheckInitialState; +using sessions_helper::GetLocalWindows; +using sessions_helper::GetSessionData; +using sessions_helper::OpenTabAndGetLocalWindows; +using sessions_helper::WindowsMatch; + +class TwoClientSessionsSyncTest : public LiveSyncTest { + public: + TwoClientSessionsSyncTest() : LiveSyncTest(TWO_CLIENT) {} + virtual ~TwoClientSessionsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientSessionsSyncTest); +}; + +static const char* kValidPassphrase = "passphrase!"; +static const char* kURL1 = "chrome://sync"; +static const char* kURL2 = "chrome://version"; + +// TODO(zea): Test each individual session command we care about separately. +// (as well as multi-window). We're currently only checking basic single-window/ +// single-tab functionality. + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, SingleClientChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + ScopedVector<SessionWindow> client0_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(0, GURL(kURL1), client0_windows.get())); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Get foreign session data from client 1. + SyncedSessionVector sessions1; + ASSERT_TRUE(GetSessionData(1, &sessions1)); + + // Verify client 1's foreign session matches client 0 current window. + ASSERT_EQ(1U, sessions1.size()); + ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, client0_windows.get())); +} + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + SingleClientEnabledEncryption) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(IsEncrypted(0, syncable::SESSIONS)); + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + SingleClientEnabledEncryptionAndChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + ScopedVector<SessionWindow> client0_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(0, GURL(kURL1), client0_windows.get())); + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Get foreign session data from client 1. + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); + SyncedSessionVector sessions1; + ASSERT_TRUE(GetSessionData(1, &sessions1)); + + // Verify client 1's foreign session matches client 0 current window. + ASSERT_EQ(1U, sessions1.size()); + ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, client0_windows.get())); +} + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + BothClientsEnabledEncryption) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + ASSERT_TRUE(EnableEncryption(1, syncable::SESSIONS)); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(IsEncrypted(0, syncable::SESSIONS)); + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); +} + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, BothChanged) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + // Open tabs on both clients and retain window information. + ScopedVector<SessionWindow> client0_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(0, GURL(kURL2), client0_windows.get())); + ScopedVector<SessionWindow> client1_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(1, GURL(kURL1), client1_windows.get())); + + // Wait for sync. + ASSERT_TRUE(AwaitQuiescence()); + + // Get foreign session data from client 0 and 1. + SyncedSessionVector sessions0; + SyncedSessionVector sessions1; + ASSERT_TRUE(GetSessionData(0, &sessions0)); + ASSERT_TRUE(GetSessionData(1, &sessions1)); + + // Verify client 1's foreign session matches client 0's current window and + // vice versa. + ASSERT_EQ(1U, sessions0.size()); + ASSERT_EQ(1U, sessions1.size()); + ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, client0_windows.get())); + ASSERT_TRUE(WindowsMatch(sessions0[0]->windows, client1_windows.get())); +} + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + FirstChangesAndSetsPassphrase) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + ScopedVector<SessionWindow> client0_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(0, GURL(kURL1), client0_windows.get())); + + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + GetClient(0)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseRequired()); + ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()-> + num_blocking_conflicting_updates); + // We have 3 non-blocking conflicts due to the two meta nodes (one for each + // client, and the one tab node). + ASSERT_EQ(3, GetClient(1)->GetLastSessionSnapshot()-> + num_conflicting_updates); // The encrypted nodes. + + GetClient(1)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->WaitForTypeEncryption(syncable::SESSIONS)); + + ASSERT_TRUE(IsEncrypted(0, syncable::SESSIONS)); + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); + // Get foreign session data from client 0 and 1. + SyncedSessionVector sessions1; + ASSERT_TRUE(GetSessionData(1, &sessions1)); + + // Verify client 1's foreign session matches client 0's current window and + // vice versa. + ASSERT_EQ(1U, sessions1.size()); + ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, client0_windows.get())); +} + +// Flaky (number of conflicting nodes is off). http://crbug.com/89604. +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + FLAKY_FirstChangesWhileSecondWaitingForPassphrase) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + GetClient(0)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseRequired()); + ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()-> + num_blocking_conflicting_updates); + // We have two non-blocking conflicts due to the two meta nodes (one for each + // client). + ASSERT_EQ(2, GetClient(1)->GetLastSessionSnapshot()-> + num_conflicting_updates); // The encrypted nodes. + + ScopedVector<SessionWindow> client0_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(0, GURL(kURL1), client0_windows.get())); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()-> + num_blocking_conflicting_updates); + ASSERT_EQ(3, GetClient(1)->GetLastSessionSnapshot()-> + num_conflicting_updates); // The encrypted nodes. + + GetClient(1)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->WaitForTypeEncryption(syncable::SESSIONS)); + + ASSERT_TRUE(IsEncrypted(0, syncable::SESSIONS)); + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); + // Get foreign session data from client 0 and 1. + SyncedSessionVector sessions1; + ASSERT_TRUE(GetSessionData(1, &sessions1)); + + // Verify client 1's foreign session matches client 0's current window and + // vice versa. + ASSERT_EQ(1U, sessions1.size()); + ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, client0_windows.get())); +} + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + SecondChangesAfterEncrAndPassphraseChange) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + GetClient(0)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseRequired()); + ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()-> + num_blocking_conflicting_updates); + // We have two non-blocking conflicts due to the two meta nodes (one for each + // client). + ASSERT_EQ(2, GetClient(1)->GetLastSessionSnapshot()-> + num_conflicting_updates); // The encrypted nodes. + + // These changes are either made with the old passphrase or not encrypted at + // all depending on when client 0's changes are propagated. + ScopedVector<SessionWindow> client1_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(1, GURL(kURL1), client1_windows.get())); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()-> + num_blocking_conflicting_updates); + ASSERT_EQ(2, GetClient(1)->GetLastSessionSnapshot()-> + num_conflicting_updates); // The same encrypted nodes. + + // At this point we enter the passphrase, triggering a resync, in which the + // local changes of client 1 get overwritten for now. + GetClient(1)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->WaitForTypeEncryption(syncable::SESSIONS)); + + ASSERT_TRUE(IsEncrypted(0, syncable::SESSIONS)); + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); + // The session data from client 1 got overwritten. As a result, client 0 + // should have no foreign session data. + SyncedSessionVector sessions0; + SyncedSessionVector sessions1; + ASSERT_FALSE(GetSessionData(0, &sessions0)); + ASSERT_FALSE(GetSessionData(1, &sessions1)); +} + +// Flaky. http://crbug.com/85294 +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + FLAKY_SecondChangesBeforeEncrAndPassphraseChange) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + // These changes are either made on client 1 without encryption. + ScopedVector<SessionWindow> client1_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(1, GURL(kURL1), client1_windows.get())); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + + // Turn encryption on client 0. Client 1's foreign will be encrypted with the + // new passphrase and synced back. It will be unable to decrypt it yet. + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + GetClient(0)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(AwaitQuiescence()); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseRequired()); + ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()-> + num_blocking_conflicting_updates); + // We have three non-blocking conflicts due to the two meta nodes (one for + // each client) and the one tab node. + ASSERT_GE(3, GetClient(1)->GetLastSessionSnapshot()-> + num_conflicting_updates); // The encrypted nodes. + + // At this point we enter the passphrase, triggering a resync. + GetClient(1)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(1)->WaitForTypeEncryption(syncable::SESSIONS)); + + ASSERT_TRUE(IsEncrypted(0, syncable::SESSIONS)); + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); + // Client 0's foreign data should match client 1's local data. Client 1's + // foreign data is empty because client 0 did not open any tabs. + SyncedSessionVector sessions0; + SyncedSessionVector sessions1; + ASSERT_TRUE(GetSessionData(0, &sessions0)); + ASSERT_FALSE(GetSessionData(1, &sessions1)); + ASSERT_EQ(1U, sessions0.size()); + ASSERT_TRUE(WindowsMatch(sessions0[0]->windows, client1_windows.get())); +} + +IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest, + BothChangeWithEncryptionAndPassphrase) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_TRUE(CheckInitialState(0)); + ASSERT_TRUE(CheckInitialState(1)); + + GetClient(0)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(0)->AwaitPassphraseAccepted()); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseRequired()); + + // These changes will sync over to client 1, who will be unable to decrypt + // them due to the missing passphrase. + ScopedVector<SessionWindow> client0_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(0, GURL(kURL1), client0_windows.get())); + ASSERT_TRUE(EnableEncryption(0, syncable::SESSIONS)); + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()-> + num_blocking_conflicting_updates); + // We have three non-blocking conflicts due to the two meta nodes (one for + // each client) and the one tab node. + ASSERT_EQ(3, GetClient(1)->GetLastSessionSnapshot()-> + num_conflicting_updates); // The encrypted nodes. + + GetClient(1)->service()->SetPassphrase(kValidPassphrase, true, true); + ASSERT_TRUE(GetClient(1)->AwaitPassphraseAccepted()); + ASSERT_FALSE(GetClient(1)->service()->IsPassphraseRequired()); + ASSERT_TRUE(GetClient(1)->WaitForTypeEncryption(syncable::SESSIONS)); + + // Open windows on client 1, which should automatically be encrypted. + ScopedVector<SessionWindow> client1_windows; + ASSERT_TRUE(OpenTabAndGetLocalWindows(1, GURL(kURL2), client1_windows.get())); + ASSERT_TRUE(GetClient(1)->AwaitMutualSyncCycleCompletion(GetClient(0))); + + ASSERT_TRUE(IsEncrypted(0, syncable::SESSIONS)); + ASSERT_TRUE(IsEncrypted(1, syncable::SESSIONS)); + // Get foreign session data from client 0 and 1. + SyncedSessionVector sessions0; + SyncedSessionVector sessions1; + ASSERT_TRUE(GetSessionData(0, &sessions0)); + ASSERT_TRUE(GetSessionData(1, &sessions1)); + + // Verify client 1's foreign session matches client 0's current window and + // vice versa. + ASSERT_EQ(1U, sessions0.size()); + ASSERT_EQ(1U, sessions1.size()); + ASSERT_TRUE(WindowsMatch(sessions1[0]->windows, client0_windows.get())); + ASSERT_TRUE(WindowsMatch(sessions0[0]->windows, client1_windows.get())); +} diff --git a/chrome/browser/sync/test/live_sync/two_client_themes_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_themes_sync_test.cc new file mode 100644 index 0000000..2ca7c3f --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_themes_sync_test.cc @@ -0,0 +1,245 @@ +// Copyright (c) 2011 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/basictypes.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/themes_helper.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" + +using themes_helper::GetCustomTheme; +using themes_helper::GetThemeID; +using themes_helper::HasOrWillHaveCustomTheme; +using themes_helper::ThemeIsPendingInstall; +using themes_helper::UseCustomTheme; +using themes_helper::UseDefaultTheme; +using themes_helper::UseNativeTheme; +using themes_helper::UsingCustomTheme; +using themes_helper::UsingDefaultTheme; +using themes_helper::UsingNativeTheme; + +class TwoClientThemesSyncTest : public LiveSyncTest { + public: + TwoClientThemesSyncTest() : LiveSyncTest(TWO_CLIENT) {} + virtual ~TwoClientThemesSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientThemesSyncTest); +}; + +// TODO(akalin): Add tests for model association (i.e., tests that +// start with SetupClients(), change the theme state, then call +// SetupSync()). + +// TCM ID - 3667311. +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, CustomTheme) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + ASSERT_FALSE(UsingCustomTheme(verifier())); + + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + // TODO(akalin): Add functions to simulate when a pending extension + // is installed as well as when a pending extension fails to + // install. + ASSERT_TRUE(ThemeIsPendingInstall(GetProfile(1), GetCustomTheme(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); +} + +// TCM ID - 3599303. +// TODO(sync): Fails on Chrome OS. See http://crbug.com/84575. +#if defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, FAILS_NativeTheme) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, NativeTheme) { +#endif // OS_CHROMEOS + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(GetProfile(1), 0); + UseCustomTheme(verifier(), 0); + + ASSERT_TRUE(AwaitQuiescence()); + + UseNativeTheme(GetProfile(0)); + UseNativeTheme(verifier()); + ASSERT_TRUE(UsingNativeTheme(GetProfile(0))); + ASSERT_TRUE(UsingNativeTheme(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + ASSERT_TRUE(UsingNativeTheme(GetProfile(0))); + ASSERT_TRUE(UsingNativeTheme(GetProfile(1))); + ASSERT_TRUE(UsingNativeTheme(verifier())); +} + +// TCM ID - 7247455. +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, DefaultTheme) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(GetProfile(1), 0); + UseCustomTheme(verifier(), 0); + + ASSERT_TRUE(AwaitQuiescence()); + + UseDefaultTheme(GetProfile(0)); + UseDefaultTheme(verifier()); + ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(verifier())); + + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(GetProfile(1))); + ASSERT_TRUE(UsingDefaultTheme(verifier())); +} + +// TCM ID - 7292065. +// TODO(sync): Fails on Chrome OS. See http://crbug.com/84575. +#if defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, FAILS_NativeDefaultRace) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, NativeDefaultRace) { +#endif // OS_CHROMEOS + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + UseNativeTheme(GetProfile(0)); + UseDefaultTheme(GetProfile(1)); + ASSERT_TRUE(UsingNativeTheme(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(GetProfile(1))); + + ASSERT_TRUE(AwaitQuiescence()); + + // TODO(akalin): Add function that compares two profiles to see if + // they're at the same state. + + ASSERT_EQ(UsingNativeTheme(GetProfile(0)), + UsingNativeTheme(GetProfile(1))); + ASSERT_EQ(UsingDefaultTheme(GetProfile(0)), + UsingDefaultTheme(GetProfile(1))); +} + +// TCM ID - 7294077. +// TODO(sync): Fails on Chrome OS. See http://crbug.com/84575. +#if defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, FAILS_CustomNativeRace) { +#else +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, CustomNativeRace) { +#endif // OS_CHROMEOS + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + UseCustomTheme(GetProfile(0), 0); + UseNativeTheme(GetProfile(1)); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_TRUE(UsingNativeTheme(GetProfile(1))); + + ASSERT_TRUE(AwaitQuiescence()); + + // TODO(akalin): Add function to wait for pending extensions to be + // installed. + + ASSERT_EQ(HasOrWillHaveCustomTheme(GetProfile(0), GetCustomTheme(0)), + HasOrWillHaveCustomTheme(GetProfile(1), GetCustomTheme(0))); +} + +// TCM ID - 7307225. +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, CustomDefaultRace) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + UseCustomTheme(GetProfile(0), 0); + UseDefaultTheme(GetProfile(1)); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_TRUE(UsingDefaultTheme(GetProfile(1))); + + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(HasOrWillHaveCustomTheme(GetProfile(0), GetCustomTheme(0)), + HasOrWillHaveCustomTheme(GetProfile(1), GetCustomTheme(0))); +} + +// TCM ID - 7264758. +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, CustomCustomRace) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // TODO(akalin): Generalize this to n clients. + + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(GetProfile(1), 1); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_EQ(GetCustomTheme(1), GetThemeID(GetProfile(1))); + + ASSERT_TRUE(AwaitQuiescence()); + + bool using_theme_0 = + (GetThemeID(GetProfile(0)) == GetCustomTheme(0)) && + HasOrWillHaveCustomTheme(GetProfile(1), GetCustomTheme(0)); + bool using_theme_1 = + HasOrWillHaveCustomTheme(GetProfile(0), GetCustomTheme(1)) && + (GetThemeID(GetProfile(1)) == GetCustomTheme(1)); + + // Equivalent to using_theme_0 xor using_theme_1. + ASSERT_NE(using_theme_0, using_theme_1); +} + +// TCM ID - 3723272. +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, DisableThemes) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + ASSERT_FALSE(UsingCustomTheme(verifier())); + + ASSERT_TRUE(GetClient(1)->DisableSyncForDatatype(syncable::THEMES)); + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + + ASSERT_TRUE(GetClient(1)->EnableSyncForDatatype(syncable::THEMES)); + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + ASSERT_TRUE(ThemeIsPendingInstall(GetProfile(1), GetCustomTheme(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); +} + +// TCM ID - 3687288. +IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, DisableSync) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + ASSERT_FALSE(UsingCustomTheme(verifier())); + + ASSERT_TRUE(GetClient(1)->DisableSyncForAllDatatypes()); + UseCustomTheme(GetProfile(0), 0); + UseCustomTheme(verifier(), 0); + ASSERT_TRUE( + GetClient(0)->AwaitSyncCycleCompletion("Installed a custom theme.")); + + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + + ASSERT_TRUE(GetClient(1)->EnableSyncForAllDatatypes()); + ASSERT_TRUE(AwaitQuiescence()); + + ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); + ASSERT_TRUE(ThemeIsPendingInstall(GetProfile(1), GetCustomTheme(0))); +} diff --git a/chrome/browser/sync/test/live_sync/two_client_typed_urls_sync_test.cc b/chrome/browser/sync/test/live_sync/two_client_typed_urls_sync_test.cc new file mode 100644 index 0000000..ce49633 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/two_client_typed_urls_sync_test.cc @@ -0,0 +1,178 @@ +// Copyright (c) 2011 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/i18n/number_formatting.h" +#include "base/memory/scoped_vector.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/sync/profile_sync_service_harness.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/typed_urls_helper.h" + +using typed_urls_helper::AddUrlToHistory; +using typed_urls_helper::AssertAllProfilesHaveSameURLsAsVerifier; +using typed_urls_helper::DeleteUrlFromHistory; +using typed_urls_helper::GetTypedUrlsFromClient; + +class TwoClientTypedUrlsSyncTest : public LiveSyncTest { + public: + TwoClientTypedUrlsSyncTest() : LiveSyncTest(TWO_CLIENT) {} + virtual ~TwoClientTypedUrlsSyncTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(TwoClientTypedUrlsSyncTest); +}; + +// TCM: 3728323 +IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, Add) { + const string16 kHistoryUrl( + ASCIIToUTF16("http://www.add-one-history.google.com/")); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Populate one client with a URL, should sync to the other. + GURL new_url(kHistoryUrl); + AddUrlToHistory(0, new_url); + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + ASSERT_EQ(new_url, urls[0].url()); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Both clients should have this URL. + AssertAllProfilesHaveSameURLsAsVerifier(); +} + +// TCM: 3705291 +IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddThenDelete) { + const string16 kHistoryUrl( + ASCIIToUTF16("http://www.add-one-history.google.com/")); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Populate one client with a URL, should sync to the other. + GURL new_url(kHistoryUrl); + AddUrlToHistory(0, new_url); + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + ASSERT_EQ(new_url, urls[0].url()); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Both clients should have this URL. + AssertAllProfilesHaveSameURLsAsVerifier(); + + // Delete from first client, should delete from second. + DeleteUrlFromHistory(0, new_url); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Neither client should have this URL. + AssertAllProfilesHaveSameURLsAsVerifier(); +} + +// TCM: 3643277 +IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, DisableEnableSync) { + const string16 kUrl1(ASCIIToUTF16("http://history1.google.com/")); + const string16 kUrl2(ASCIIToUTF16("http://history2.google.com/")); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Disable typed url sync for one client, leave it active for the other. + GetClient(0)->DisableSyncForDatatype(syncable::TYPED_URLS); + + // Add one URL to non-syncing client, add a different URL to the other, + // wait for sync cycle to complete. No data should be exchanged. + GURL url1(kUrl1); + GURL url2(kUrl2); + AddUrlToHistory(0, url1); + AddUrlToHistory(1, url2); + ASSERT_TRUE(AwaitQuiescence()); + + // Make sure that no data was exchanged. + std::vector<history::URLRow> post_sync_urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, post_sync_urls.size()); + ASSERT_EQ(url1, post_sync_urls[0].url()); + post_sync_urls = GetTypedUrlsFromClient(1); + ASSERT_EQ(1U, post_sync_urls.size()); + ASSERT_EQ(url2, post_sync_urls[0].url()); + + // Enable typed url sync, make both URLs are synced to each client. + GetClient(0)->EnableSyncForDatatype(syncable::TYPED_URLS); + ASSERT_TRUE(AwaitQuiescence()); + + AssertAllProfilesHaveSameURLsAsVerifier(); +} + +IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddOneDeleteOther) { + const string16 kHistoryUrl( + ASCIIToUTF16("http://www.add-one-delete-history.google.com/")); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Populate one client with a URL, should sync to the other. + GURL new_url(kHistoryUrl); + AddUrlToHistory(0, new_url); + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + ASSERT_EQ(new_url, urls[0].url()); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Both clients should have this URL. + AssertAllProfilesHaveSameURLsAsVerifier(); + + // Now, delete the URL from the second client. + DeleteUrlFromHistory(1, new_url); + urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Both clients should have this URL removed. + AssertAllProfilesHaveSameURLsAsVerifier(); +} + +IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, + AddOneDeleteOtherAddAgain) { + const string16 kHistoryUrl( + ASCIIToUTF16("http://www.add-delete-add-history.google.com/")); + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + + // Populate one client with a URL, should sync to the other. + GURL new_url(kHistoryUrl); + AddUrlToHistory(0, new_url); + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + ASSERT_EQ(new_url, urls[0].url()); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Both clients should have this URL. + AssertAllProfilesHaveSameURLsAsVerifier(); + + // Now, delete the URL from the second client. + DeleteUrlFromHistory(1, new_url); + urls = GetTypedUrlsFromClient(0); + ASSERT_EQ(1U, urls.size()); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Both clients should have this URL removed. + AssertAllProfilesHaveSameURLsAsVerifier(); + + // Add it to the first client again, should succeed (tests that the deletion + // properly disassociates that URL). + AddUrlToHistory(0, new_url); + + // Let sync finish. + ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1))); + + // Both clients should have this URL added again. + AssertAllProfilesHaveSameURLsAsVerifier(); +} diff --git a/chrome/browser/sync/test/live_sync/typed_urls_helper.cc b/chrome/browser/sync/test/live_sync/typed_urls_helper.cc new file mode 100644 index 0000000..0a0cc84 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/typed_urls_helper.cc @@ -0,0 +1,184 @@ +// Copyright (c) 2011 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/live_sync/typed_urls_helper.h" + +#include "base/synchronization/waitable_event.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/history/history.h" +#include "chrome/browser/history/history_backend.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/live_sync/live_sync_test.h" +#include "chrome/browser/sync/test/live_sync/sync_datatype_helper.h" +#include "content/browser/cancelable_request.h" + +using sync_datatype_helper::test; + +namespace { + +class FlushHistoryDBQueueTask : public HistoryDBTask { + public: + explicit FlushHistoryDBQueueTask(base::WaitableEvent* event) + : wait_event_(event) {} + virtual bool RunOnDBThread(history::HistoryBackend* backend, + history::HistoryDatabase* db) { + wait_event_->Signal(); + return true; + } + + virtual void DoneRunOnMainThread() {} + private: + base::WaitableEvent* wait_event_; +}; + +class GetTypedUrlsTask : public HistoryDBTask { + public: + GetTypedUrlsTask(std::vector<history::URLRow>* rows, + base::WaitableEvent* event) + : rows_(rows), wait_event_(event) {} + + virtual bool RunOnDBThread(history::HistoryBackend* backend, + history::HistoryDatabase* db) { + // Fetch the typed URLs. + backend->GetAllTypedURLs(rows_); + wait_event_->Signal(); + return true; + } + + virtual void DoneRunOnMainThread() {} + private: + std::vector<history::URLRow>* rows_; + base::WaitableEvent* wait_event_; +}; + +// Waits for the history DB thread to finish executing its current set of +// tasks. +void WaitForHistoryDBThread(int index) { + CancelableRequestConsumer cancelable_consumer; + HistoryService* service = + test()->GetProfile(index)->GetHistoryServiceWithoutCreating(); + base::WaitableEvent wait_event(true, false); + service->ScheduleDBTask(new FlushHistoryDBQueueTask(&wait_event), + &cancelable_consumer); + wait_event.Wait(); +} + +// Creates a URLRow in the specified HistoryService. +void AddToHistory(HistoryService* service, + const GURL& url, + const base::Time& timestamp) { + service->AddPage(url, + timestamp, + NULL, // scope + 1234, // page_id + GURL(), // referrer + PageTransition::TYPED, + history::RedirectList(), + history::SOURCE_BROWSED, + false); +} + +std::vector<history::URLRow> GetTypedUrlsFromHistoryService( + HistoryService* service) { + CancelableRequestConsumer cancelable_consumer; + std::vector<history::URLRow> rows; + base::WaitableEvent wait_event(true, false); + service->ScheduleDBTask(new GetTypedUrlsTask(&rows, &wait_event), + &cancelable_consumer); + wait_event.Wait(); + return rows; +} + +static base::Time* timestamp = NULL; + +} // namespace + +namespace typed_urls_helper { + +std::vector<history::URLRow> GetTypedUrlsFromClient(int index) { + HistoryService* service = + test()->GetProfile(index)->GetHistoryServiceWithoutCreating(); + return GetTypedUrlsFromHistoryService(service); +} + +base::Time GetTimestamp() { + // The history subsystem doesn't like identical timestamps for page visits, + // and it will massage the visit timestamps if we try to use identical + // values, which can lead to spurious errors. So make sure all timestamps + // are unique. + if (!::timestamp) + ::timestamp = new base::Time(base::Time::Now()); + base::Time original = *::timestamp; + *::timestamp += base::TimeDelta::FromMilliseconds(1); + return original; +} + +void AddUrlToHistory(int index, const GURL& url) { + base::Time timestamp = GetTimestamp(); + AddToHistory(test()->GetProfile(index)->GetHistoryServiceWithoutCreating(), + url, + timestamp); + if (test()->use_verifier()) + AddToHistory( + test()->verifier()->GetHistoryService(Profile::IMPLICIT_ACCESS), + url, + timestamp); + + // Wait until the AddPage() request has completed so we know the change has + // filtered down to the sync observers (don't need to wait for the + // verifier profile since it doesn't sync). + WaitForHistoryDBThread(index); +} + +void DeleteUrlFromHistory(int index, const GURL& url) { + test()->GetProfile(index)->GetHistoryServiceWithoutCreating()->DeleteURL(url); + if (test()->use_verifier()) + test()->verifier()->GetHistoryService(Profile::IMPLICIT_ACCESS)-> + DeleteURL(url); + WaitForHistoryDBThread(index); +} + +void AssertURLRowVectorsAreEqual( + const std::vector<history::URLRow>& left, + const std::vector<history::URLRow>& right) { + ASSERT_EQ(left.size(), right.size()); + for (size_t i = 0; i < left.size(); ++i) { + // URLs could be out-of-order, so look for a matching URL in the second + // array. + bool found = false; + for (size_t j = 0; j < right.size(); ++j) { + if (left[i].url() == right[j].url()) { + AssertURLRowsAreEqual(left[i], right[j]); + found = true; + break; + } + } + ASSERT_TRUE(found); + } +} + +void AssertURLRowsAreEqual( + const history::URLRow& left, const history::URLRow& right) { + ASSERT_EQ(left.url(), right.url()); + ASSERT_EQ(left.title(), right.title()); + ASSERT_EQ(left.visit_count(), right.visit_count()); + ASSERT_EQ(left.typed_count(), right.typed_count()); + ASSERT_EQ(left.last_visit(), right.last_visit()); + ASSERT_EQ(left.hidden(), right.hidden()); +} + +void AssertAllProfilesHaveSameURLsAsVerifier() { + HistoryService* verifier_service = + test()->verifier()->GetHistoryService(Profile::IMPLICIT_ACCESS); + std::vector<history::URLRow> verifier_urls = + GetTypedUrlsFromHistoryService(verifier_service); + for (int i = 0; i < test()->num_clients(); ++i) { + std::vector<history::URLRow> urls = GetTypedUrlsFromClient(i); + AssertURLRowVectorsAreEqual(verifier_urls, urls); + } +} + +} // namespace typed_urls_helper diff --git a/chrome/browser/sync/test/live_sync/typed_urls_helper.h b/chrome/browser/sync/test/live_sync/typed_urls_helper.h new file mode 100644 index 0000000..5447f62 --- /dev/null +++ b/chrome/browser/sync/test/live_sync/typed_urls_helper.h @@ -0,0 +1,51 @@ +// Copyright (c) 2011 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_LIVE_SYNC_TYPED_URLS_HELPER_H_ +#define CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_TYPED_URLS_HELPER_H_ +#pragma once + +#include <vector> + +#include "chrome/browser/history/history_types.h" + +namespace base { +class Time; +} + +namespace typed_urls_helper { + +// Gets the typed URLs from a specific sync profile. +std::vector<history::URLRow> GetTypedUrlsFromClient(int index); + +// Adds a URL to the history DB for a specific sync profile (just registers a +// new visit if the URL already exists). +void AddUrlToHistory(int index, const GURL& url); + +// Deletes a URL from the history DB for a specific sync profile. +void DeleteUrlFromHistory(int index, const GURL& url); + +// Returns true if all clients match the verifier profile. +void AssertAllProfilesHaveSameURLsAsVerifier(); + +// Checks that the two vectors contain the same set of URLRows (possibly in +// a different order). +void AssertURLRowVectorsAreEqual( + const std::vector<history::URLRow>& left, + const std::vector<history::URLRow>& right); + +// Checks that the passed URLRows are equivalent. +void AssertURLRowsAreEqual(const history::URLRow& left, + const history::URLRow& right); + +// Returns a unique timestamp to use when generating page visits +// (HistoryService does not like having identical timestamps and will modify +// the timestamps behind the scenes if it encounters them, which leads to +// spurious test failures when the resulting timestamps aren't what we +// expect). +base::Time GetTimestamp(); + +} // namespace typed_urls_helper + +#endif // CHROME_BROWSER_SYNC_TEST_LIVE_SYNC_TYPED_URLS_HELPER_H_ diff --git a/chrome/browser/sync/test/null_directory_change_delegate.cc b/chrome/browser/sync/test/null_directory_change_delegate.cc new file mode 100644 index 0000000..7b2ec71 --- /dev/null +++ b/chrome/browser/sync/test/null_directory_change_delegate.cc @@ -0,0 +1,27 @@ +// Copyright (c) 2011 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/null_directory_change_delegate.h" + +namespace syncable { + +NullDirectoryChangeDelegate::~NullDirectoryChangeDelegate() {} + +void NullDirectoryChangeDelegate::HandleCalculateChangesChangeEventFromSyncApi( + const EntryKernelMutationSet& mutations, + BaseTransaction* trans) {} + +void NullDirectoryChangeDelegate::HandleCalculateChangesChangeEventFromSyncer( + const EntryKernelMutationSet& mutations, + BaseTransaction* trans) {} + +ModelTypeBitSet NullDirectoryChangeDelegate::HandleTransactionEndingChangeEvent( + BaseTransaction* trans) { + return ModelTypeBitSet(); +} + +void NullDirectoryChangeDelegate::HandleTransactionCompleteChangeEvent( + const ModelTypeBitSet& models_with_changes) {} + +} // namespace syncable diff --git a/chrome/browser/sync/test/null_directory_change_delegate.h b/chrome/browser/sync/test/null_directory_change_delegate.h new file mode 100644 index 0000000..1b8518a --- /dev/null +++ b/chrome/browser/sync/test/null_directory_change_delegate.h @@ -0,0 +1,33 @@ +// Copyright (c) 2011 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_NULL_DIRECTORY_CHANGE_DELEGATE_H_ +#define CHROME_BROWSER_SYNC_TEST_NULL_DIRECTORY_CHANGE_DELEGATE_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/sync/syncable/directory_change_delegate.h" + +namespace syncable { + +// DirectoryChangeDelegate that does nothing in all delegate methods. +class NullDirectoryChangeDelegate : public DirectoryChangeDelegate { + public: + virtual ~NullDirectoryChangeDelegate(); + + virtual void HandleCalculateChangesChangeEventFromSyncApi( + const EntryKernelMutationSet& mutations, + BaseTransaction* trans) OVERRIDE; + virtual void HandleCalculateChangesChangeEventFromSyncer( + const EntryKernelMutationSet& mutations, + BaseTransaction* trans) OVERRIDE; + virtual ModelTypeBitSet HandleTransactionEndingChangeEvent( + BaseTransaction* trans) OVERRIDE; + virtual void HandleTransactionCompleteChangeEvent( + const ModelTypeBitSet& models_with_changes) OVERRIDE; +}; + +} // namespace syncable + +#endif // CHROME_BROWSER_SYNC_TEST_NULL_DIRECTORY_CHANGE_DELEGATE_H_ diff --git a/chrome/browser/sync/test/sessions/test_scoped_session_event_listener.h b/chrome/browser/sync/test/sessions/test_scoped_session_event_listener.h new file mode 100644 index 0000000..15fc68c --- /dev/null +++ b/chrome/browser/sync/test/sessions/test_scoped_session_event_listener.h @@ -0,0 +1,36 @@ +// Copyright (c) 2010 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_SESSIONS_TEST_SCOPED_SESSION_EVENT_LISTENER_H_ +#define CHROME_BROWSER_SYNC_TEST_SESSIONS_TEST_SCOPED_SESSION_EVENT_LISTENER_H_ +#pragma once + +#include "chrome/browser/sync/sessions/sync_session_context.h" + +namespace browser_sync { +namespace sessions { + +// Installs a SyncEventListener to a given session context for the lifetime of +// the TestScopedSessionEventListener. +class TestScopedSessionEventListener { + public: + TestScopedSessionEventListener( + SyncSessionContext* context, + SyncEngineEventListener* listener) + : context_(context), listener_(listener) { + context->listeners_.AddObserver(listener); + } + ~TestScopedSessionEventListener() { + context_->listeners_.RemoveObserver(listener_); + } + private: + SyncSessionContext* context_; + SyncEngineEventListener* listener_; + DISALLOW_COPY_AND_ASSIGN(TestScopedSessionEventListener); +}; + +} // namespace sessions +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_SESSIONS_TEST_SCOPED_SESSION_EVENT_LISTENER_H_ diff --git a/chrome/browser/sync/test/test_http_bridge_factory.cc b/chrome/browser/sync/test/test_http_bridge_factory.cc new file mode 100644 index 0000000..a74cf4b --- /dev/null +++ b/chrome/browser/sync/test/test_http_bridge_factory.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2011 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/test_http_bridge_factory.h" + +namespace browser_sync { + +bool TestHttpBridge::MakeSynchronousPost(int* os_error_code, + int* response_code) { + return false; +} + +int TestHttpBridge::GetResponseContentLength() const { + return 0; +} + +const char* TestHttpBridge::GetResponseContent() const { + return 0; +} + +const std::string TestHttpBridge::GetResponseHeaderValue( + const std::string &) const { + return std::string(); +} + +void TestHttpBridge::Abort() { +} + +TestHttpBridgeFactory::TestHttpBridgeFactory() {} + +TestHttpBridgeFactory::~TestHttpBridgeFactory() {} + +sync_api::HttpPostProviderInterface* TestHttpBridgeFactory::Create() { + return new TestHttpBridge(); +} + +void TestHttpBridgeFactory::Destroy(sync_api::HttpPostProviderInterface* http) { + delete http; +} + +} // namespace browser_sync diff --git a/chrome/browser/sync/test/test_http_bridge_factory.h b/chrome/browser/sync/test/test_http_bridge_factory.h new file mode 100644 index 0000000..ebfc577 --- /dev/null +++ b/chrome/browser/sync/test/test_http_bridge_factory.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 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_TEST_HTTP_BRIDGE_FACTORY_H_ +#define CHROME_BROWSER_SYNC_TEST_TEST_HTTP_BRIDGE_FACTORY_H_ +#pragma once + +#include "base/compiler_specific.h" +#include "chrome/browser/sync/internal_api/http_post_provider_interface.h" +#include "chrome/browser/sync/internal_api/http_post_provider_factory.h" + +namespace browser_sync { + +class TestHttpBridge : public sync_api::HttpPostProviderInterface { + public: + // Begin sync_api::HttpPostProviderInterface implementation: + virtual void SetUserAgent(const char* user_agent) OVERRIDE {} + + virtual void SetExtraRequestHeaders(const char * headers) OVERRIDE {} + + virtual void SetURL(const char* url, int port) OVERRIDE {} + + virtual void SetPostPayload(const char* content_type, + int content_length, + const char* content) OVERRIDE {} + + virtual bool MakeSynchronousPost(int* os_error_code, + int* response_code) OVERRIDE; + + virtual int GetResponseContentLength() const OVERRIDE; + + virtual const char* GetResponseContent() const OVERRIDE; + + virtual const std::string GetResponseHeaderValue( + const std::string&) const OVERRIDE; + + virtual void Abort(); + // End sync_api::HttpPostProviderInterface implementation. +}; + +class TestHttpBridgeFactory : public sync_api::HttpPostProviderFactory { + public: + TestHttpBridgeFactory(); + virtual ~TestHttpBridgeFactory(); + + // sync_api::HttpPostProviderFactory: + virtual sync_api::HttpPostProviderInterface* Create() OVERRIDE; + virtual void Destroy(sync_api::HttpPostProviderInterface* http) OVERRIDE; +}; + +} // namespace browser_sync + +#endif // CHROME_BROWSER_SYNC_TEST_TEST_HTTP_BRIDGE_FACTORY_H_ diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc index 95557ca..ec5ac17 100644 --- a/chrome/browser/sync/test_profile_sync_service.cc +++ b/chrome/browser/sync/test_profile_sync_service.cc @@ -14,8 +14,8 @@ #include "chrome/browser/sync/signin_manager.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" +#include "chrome/browser/sync/test/test_http_bridge_factory.h" #include "chrome/common/chrome_notification_types.h" -#include "chrome/test/sync/test_http_bridge_factory.h" using browser_sync::ModelSafeRoutingInfo; using browser_sync::sessions::ErrorCounters; diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h index 4384723..743cdeb 100644 --- a/chrome/browser/sync/test_profile_sync_service.h +++ b/chrome/browser/sync/test_profile_sync_service.h @@ -11,8 +11,8 @@ #include "base/compiler_specific.h" #include "chrome/browser/sync/glue/data_type_manager_impl.h" #include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/test/engine/test_id_factory.h" #include "chrome/test/base/profile_mock.h" -#include "chrome/test/sync/engine/test_id_factory.h" #include "testing/gmock/include/gmock/gmock.h" class Profile; |