1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync/glue/extensions_activity_monitor.h" 6 7 #include "base/files/file_path.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/path_service.h" 10 #include "base/values.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h" 13 #include "chrome/common/chrome_paths.h" 14 #include "content/public/browser/notification_service.h" 15 #include "content/public/test/test_browser_thread_bundle.h" 16 #include "extensions/common/extension.h" 17 #include "extensions/common/manifest_constants.h" 18 #include "sync/util/extensions_activity.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 using extensions::Extension; 22 23 namespace browser_sync { 24 25 namespace { 26 27 namespace keys = extensions::manifest_keys; 28 29 // Create and return an extension with the given path. 30 scoped_refptr<Extension> MakeExtension(const std::string& name) { 31 base::FilePath path; 32 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 33 path = path.AppendASCII(name); 34 35 base::DictionaryValue value; 36 value.SetString(keys::kVersion, "1.0.0.0"); 37 value.SetString(keys::kName, name); 38 std::string error; 39 scoped_refptr<Extension> extension(Extension::Create( 40 path, extensions::Manifest::INVALID_LOCATION, value, 41 Extension::NO_FLAGS, &error)); 42 EXPECT_TRUE(error.empty()); 43 return extension; 44 } 45 46 // Fire a bookmarks API event from the given extension the given 47 // number of times. 48 template <class T> 49 void FireBookmarksApiEvent( 50 const scoped_refptr<Extension>& extension, int repeats) { 51 scoped_refptr<T> bookmarks_function(new T()); 52 bookmarks_function->set_name(T::function_name()); 53 for (int i = 0; i < repeats; i++) { 54 content::NotificationService::current()->Notify( 55 extensions::NOTIFICATION_EXTENSION_BOOKMARKS_API_INVOKED, 56 content::Source<Extension>(extension.get()), 57 content::Details<const extensions::BookmarksFunction>( 58 bookmarks_function.get())); 59 } 60 } 61 62 class SyncChromeExtensionsActivityMonitorTest : public testing::Test { 63 public: 64 SyncChromeExtensionsActivityMonitorTest() 65 : thread_bundle_(content::TestBrowserThreadBundle::DEFAULT), 66 extension1_(MakeExtension("extension1")), 67 extension2_(MakeExtension("extension2")), 68 id1_(extension1_->id()), 69 id2_(extension2_->id()) {} 70 virtual ~SyncChromeExtensionsActivityMonitorTest() {} 71 72 private: 73 content::TestBrowserThreadBundle thread_bundle_; 74 75 protected: 76 ExtensionsActivityMonitor monitor_; 77 scoped_refptr<Extension> extension1_; 78 scoped_refptr<Extension> extension2_; 79 // IDs of |extension{1,2}_|. 80 const std::string& id1_; 81 const std::string& id2_; 82 }; 83 84 // NOTE: The tests below are DISABLED because they're flaky: 85 // https://code.google.com/p/chromium/issues/detail?id=172002 86 87 // Fire some mutating bookmark API events with extension 1, then fire 88 // some mutating and non-mutating bookmark API events with extension 89 // 2. Only the mutating events should be recorded by the 90 // syncer::ExtensionsActivityMonitor. 91 TEST_F(SyncChromeExtensionsActivityMonitorTest, DISABLED_Basic) { 92 FireBookmarksApiEvent<extensions::BookmarksRemoveFunction>(extension1_, 1); 93 FireBookmarksApiEvent<extensions::BookmarksMoveFunction>(extension1_, 1); 94 FireBookmarksApiEvent<extensions::BookmarksUpdateFunction>(extension1_, 2); 95 FireBookmarksApiEvent<extensions::BookmarksCreateFunction>(extension1_, 3); 96 FireBookmarksApiEvent<extensions::BookmarksSearchFunction>(extension1_, 5); 97 const uint32 writes_by_extension1 = 1 + 1 + 2 + 3; 98 99 FireBookmarksApiEvent<extensions::BookmarksRemoveTreeFunction>( 100 extension2_, 8); 101 FireBookmarksApiEvent<extensions::BookmarksGetSubTreeFunction>( 102 extension2_, 13); 103 FireBookmarksApiEvent<extensions::BookmarksGetChildrenFunction>( 104 extension2_, 21); 105 FireBookmarksApiEvent<extensions::BookmarksGetTreeFunction>(extension2_, 33); 106 const uint32 writes_by_extension2 = 8; 107 108 syncer::ExtensionsActivity::Records results; 109 monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); 110 111 EXPECT_EQ(2U, results.size()); 112 EXPECT_TRUE(results.find(id1_) != results.end()); 113 EXPECT_TRUE(results.find(id2_) != results.end()); 114 EXPECT_EQ(writes_by_extension1, results[id1_].bookmark_write_count); 115 EXPECT_EQ(writes_by_extension2, results[id2_].bookmark_write_count); 116 } 117 118 // Fire some mutating bookmark API events with both extensions. Then 119 // get the records, fire some more mutating and non-mutating events, 120 // and put the old records back. Those should be merged with the new 121 // records correctly. 122 TEST_F(SyncChromeExtensionsActivityMonitorTest, DISABLED_Put) { 123 FireBookmarksApiEvent<extensions::BookmarksCreateFunction>(extension1_, 5); 124 FireBookmarksApiEvent<extensions::BookmarksMoveFunction>(extension2_, 8); 125 126 syncer::ExtensionsActivity::Records results; 127 monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); 128 129 EXPECT_EQ(2U, results.size()); 130 EXPECT_EQ(5U, results[id1_].bookmark_write_count); 131 EXPECT_EQ(8U, results[id2_].bookmark_write_count); 132 133 FireBookmarksApiEvent<extensions::BookmarksGetTreeFunction>(extension2_, 3); 134 FireBookmarksApiEvent<extensions::BookmarksUpdateFunction>(extension2_, 2); 135 136 // Simulate a commit failure, which augments the active record set with the 137 // refugee records. 138 monitor_.GetExtensionsActivity()->PutRecords(results); 139 syncer::ExtensionsActivity::Records new_records; 140 monitor_.GetExtensionsActivity()->GetAndClearRecords(&new_records); 141 142 EXPECT_EQ(2U, results.size()); 143 EXPECT_EQ(id1_, new_records[id1_].extension_id); 144 EXPECT_EQ(id2_, new_records[id2_].extension_id); 145 EXPECT_EQ(5U, new_records[id1_].bookmark_write_count); 146 EXPECT_EQ(8U + 2U, new_records[id2_].bookmark_write_count); 147 } 148 149 // Fire some mutating bookmark API events and get the records multiple 150 // times. The mintor should correctly clear its records every time 151 // they're returned. 152 TEST_F(SyncChromeExtensionsActivityMonitorTest, DISABLED_MultiGet) { 153 FireBookmarksApiEvent<extensions::BookmarksCreateFunction>(extension1_, 5); 154 155 syncer::ExtensionsActivity::Records results; 156 monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); 157 158 EXPECT_EQ(1U, results.size()); 159 EXPECT_EQ(5U, results[id1_].bookmark_write_count); 160 161 monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); 162 EXPECT_TRUE(results.empty()); 163 164 FireBookmarksApiEvent<extensions::BookmarksCreateFunction>(extension1_, 3); 165 monitor_.GetExtensionsActivity()->GetAndClearRecords(&results); 166 167 EXPECT_EQ(1U, results.size()); 168 EXPECT_EQ(3U, results[id1_].bookmark_write_count); 169 } 170 171 } // namespace 172 173 } // namespace browser_sync 174