// Copyright 2013 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/glue/extensions_activity_monitor.h" #include "base/files/file_path.h" #include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/values.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h" #include "chrome/common/chrome_paths.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_constants.h" #include "sync/util/extensions_activity.h" #include "testing/gtest/include/gtest/gtest.h" using extensions::Extension; namespace browser_sync { namespace { namespace keys = extensions::manifest_keys; // Create and return an extension with the given path. scoped_refptr MakeExtension(const std::string& name) { base::FilePath path; EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); path = path.AppendASCII(name); base::DictionaryValue value; value.SetString(keys::kVersion, "1.0.0.0"); value.SetString(keys::kName, name); std::string error; scoped_refptr extension(Extension::Create( path, extensions::Manifest::INVALID_LOCATION, value, Extension::NO_FLAGS, &error)); EXPECT_TRUE(error.empty()); return extension; } // Fire a bookmarks API event from the given extension the given // number of times. template void FireBookmarksApiEvent( const scoped_refptr& extension, int repeats) { scoped_refptr bookmarks_function(new T()); bookmarks_function->set_name(T::function_name()); for (int i = 0; i < repeats; i++) { content::NotificationService::current()->Notify( extensions::NOTIFICATION_EXTENSION_BOOKMARKS_API_INVOKED, content::Source(extension.get()), content::Details( bookmarks_function.get())); } } class SyncChromeExtensionsActivityMonitorTest : public testing::Test { public: SyncChromeExtensionsActivityMonitorTest() : thread_bundle_(content::TestBrowserThreadBundle::DEFAULT), extension1_(MakeExtension("extension1")), extension2_(MakeExtension("extension2")), id1_(extension1_->id()), id2_(extension2_->id()) {} virtual ~SyncChromeExtensionsActivityMonitorTest() {} private: content::TestBrowserThreadBundle thread_bundle_; protected: ExtensionsActivityMonitor monitor_; scoped_refptr extension1_; scoped_refptr extension2_; // IDs of |extension{1,2}_|. const std::string& id1_; const std::string& id2_; }; // NOTE: The tests below are DISABLED because they're flaky: // https://code.google.com/p/chromium/issues/detail?id=172002 // Fire some mutating bookmark API events with extension 1, then fire // some mutating and non-mutating bookmark API events with extension // 2. Only the mutating events should be recorded by the // syncer::ExtensionsActivityMonitor. TEST_F(SyncChromeExtensionsActivityMonitorTest, DISABLED_Basic) { FireBookmarksApiEvent(extension1_, 1); FireBookmarksApiEvent(extension1_, 1); FireBookmarksApiEvent(extension1_, 2); FireBookmarksApiEvent(extension1_, 3); FireBookmarksApiEvent(extension1_, 5); const uint32 writes_by_extension1 = 1 + 1 + 2 + 3; FireBookmarksApiEvent( extension2_, 8); FireBookmarksApiEvent( extension2_, 13); FireBookmarksApiEvent( extension2_, 21); FireBookmarksApiEvent(extension2_, 33); const uint32 writes_by_extension2 = 8; syncer::ExtensionsActivity::Records results; monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); EXPECT_EQ(2U, results.size()); EXPECT_TRUE(results.find(id1_) != results.end()); EXPECT_TRUE(results.find(id2_) != results.end()); EXPECT_EQ(writes_by_extension1, results[id1_].bookmark_write_count); EXPECT_EQ(writes_by_extension2, results[id2_].bookmark_write_count); } // Fire some mutating bookmark API events with both extensions. Then // get the records, fire some more mutating and non-mutating events, // and put the old records back. Those should be merged with the new // records correctly. TEST_F(SyncChromeExtensionsActivityMonitorTest, DISABLED_Put) { FireBookmarksApiEvent(extension1_, 5); FireBookmarksApiEvent(extension2_, 8); syncer::ExtensionsActivity::Records results; monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); EXPECT_EQ(2U, results.size()); EXPECT_EQ(5U, results[id1_].bookmark_write_count); EXPECT_EQ(8U, results[id2_].bookmark_write_count); FireBookmarksApiEvent(extension2_, 3); FireBookmarksApiEvent(extension2_, 2); // Simulate a commit failure, which augments the active record set with the // refugee records. monitor_.GetExtensionsActivity()->PutRecords(results); syncer::ExtensionsActivity::Records new_records; monitor_.GetExtensionsActivity()->GetAndClearRecords(&new_records); EXPECT_EQ(2U, results.size()); EXPECT_EQ(id1_, new_records[id1_].extension_id); EXPECT_EQ(id2_, new_records[id2_].extension_id); EXPECT_EQ(5U, new_records[id1_].bookmark_write_count); EXPECT_EQ(8U + 2U, new_records[id2_].bookmark_write_count); } // Fire some mutating bookmark API events and get the records multiple // times. The mintor should correctly clear its records every time // they're returned. TEST_F(SyncChromeExtensionsActivityMonitorTest, DISABLED_MultiGet) { FireBookmarksApiEvent(extension1_, 5); syncer::ExtensionsActivity::Records results; monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); EXPECT_EQ(1U, results.size()); EXPECT_EQ(5U, results[id1_].bookmark_write_count); monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); EXPECT_TRUE(results.empty()); FireBookmarksApiEvent(extension1_, 3); monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); EXPECT_EQ(1U, results.size()); EXPECT_EQ(3U, results[id1_].bookmark_write_count); } } // namespace } // namespace browser_sync