• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/sync/util/extensions_activity_monitor.h"
6 
7 #include "base/file_path.h"
8 #include "base/string_util.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_bookmarks_module.h"
12 #include "chrome/common/extensions/extension.h"
13 #include "chrome/common/extensions/extension_constants.h"
14 #include "content/browser/browser_thread.h"
15 #include "content/common/notification_service.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 using browser_sync::ExtensionsActivityMonitor;
19 namespace keys = extension_manifest_keys;
20 
21 namespace {
22 
23 const FilePath::CharType kTestExtensionPath1[] =
24 #if defined(OS_POSIX)
25     FILE_PATH_LITERAL("/testextension1");
26 #elif defined(OS_WIN)
27     FILE_PATH_LITERAL("c:\\testextension1");
28 #endif
29 
30 const FilePath::CharType kTestExtensionPath2[] =
31 #if defined(OS_POSIX)
32     FILE_PATH_LITERAL("/testextension2");
33 #elif defined(OS_WIN)
34     FILE_PATH_LITERAL("c:\\testextension2");
35 #endif
36 
37 const char* kTestExtensionVersion = "1.0.0.0";
38 const char* kTestExtensionName = "foo extension";
39 
40 template <class FunctionType>
41 class BookmarkAPIEventTask : public Task {
42  public:
BookmarkAPIEventTask(FunctionType * t,Extension * e,size_t repeats,base::WaitableEvent * done)43   BookmarkAPIEventTask(FunctionType* t, Extension* e, size_t repeats,
44                        base::WaitableEvent* done) :
45        extension_(e), function_(t), repeats_(repeats), done_(done) {}
Run()46    virtual void Run() {
47      for (size_t i = 0; i < repeats_; i++) {
48        NotificationService::current()->Notify(
49            NotificationType::EXTENSION_BOOKMARKS_API_INVOKED,
50            Source<Extension>(extension_.get()),
51            Details<const BookmarksFunction>(function_.get()));
52      }
53      done_->Signal();
54    }
55  private:
56   scoped_refptr<Extension> extension_;
57   scoped_refptr<FunctionType> function_;
58   size_t repeats_;
59   base::WaitableEvent* done_;
60 
61   DISALLOW_COPY_AND_ASSIGN(BookmarkAPIEventTask);
62 };
63 
64 class BookmarkAPIEventGenerator {
65  public:
BookmarkAPIEventGenerator()66   BookmarkAPIEventGenerator() {}
~BookmarkAPIEventGenerator()67   virtual ~BookmarkAPIEventGenerator() {}
68   template <class T>
NewEvent(const FilePath::StringType & extension_path,T * bookmarks_function,size_t repeats)69   void NewEvent(const FilePath::StringType& extension_path,
70       T* bookmarks_function, size_t repeats) {
71     std::string error;
72     DictionaryValue input;
73     input.SetString(keys::kVersion, kTestExtensionVersion);
74     input.SetString(keys::kName, kTestExtensionName);
75     scoped_refptr<Extension> extension(Extension::Create(
76         FilePath(extension_path), Extension::INVALID, input,
77         Extension::STRICT_ERROR_CHECKS, &error));
78     bookmarks_function->set_name(T::function_name());
79     base::WaitableEvent done_event(false, false);
80     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
81         new BookmarkAPIEventTask<T>(bookmarks_function, extension,
82                                     repeats, &done_event));
83     done_event.Wait();
84   }
85 
86  private:
87   DISALLOW_COPY_AND_ASSIGN(BookmarkAPIEventGenerator);
88 };
89 }  // namespace
90 
91 class DoUIThreadSetupTask : public Task {
92  public:
DoUIThreadSetupTask(NotificationService ** service,base::WaitableEvent * done)93   DoUIThreadSetupTask(NotificationService** service,
94                       base::WaitableEvent* done)
95       : service_(service), signal_when_done_(done) {}
~DoUIThreadSetupTask()96   virtual ~DoUIThreadSetupTask() {}
Run()97   virtual void Run() {
98     *service_ = new NotificationService();
99     signal_when_done_->Signal();
100   }
101  private:
102   NotificationService** service_;
103   base::WaitableEvent* signal_when_done_;
104   DISALLOW_COPY_AND_ASSIGN(DoUIThreadSetupTask);
105 };
106 
107 class ExtensionsActivityMonitorTest : public testing::Test {
108  public:
ExtensionsActivityMonitorTest()109   ExtensionsActivityMonitorTest() : service_(NULL),
110       ui_thread_(BrowserThread::UI) { }
~ExtensionsActivityMonitorTest()111   virtual ~ExtensionsActivityMonitorTest() {}
112 
SetUp()113   virtual void SetUp() {
114     ui_thread_.Start();
115     base::WaitableEvent service_created(false, false);
116     ui_thread_.message_loop()->PostTask(FROM_HERE,
117         new DoUIThreadSetupTask(&service_, &service_created));
118     service_created.Wait();
119   }
120 
TearDown()121   virtual void TearDown() {
122     ui_thread_.message_loop()->DeleteSoon(FROM_HERE, service_);
123     ui_thread_.Stop();
124   }
125 
ui_loop()126   MessageLoop* ui_loop() { return ui_thread_.message_loop(); }
127 
GetExtensionIdForPath(const FilePath::StringType & extension_path)128   static std::string GetExtensionIdForPath(
129       const FilePath::StringType& extension_path) {
130     std::string error;
131     DictionaryValue input;
132     input.SetString(keys::kVersion, kTestExtensionVersion);
133     input.SetString(keys::kName, kTestExtensionName);
134     scoped_refptr<Extension> extension(Extension::Create(
135         FilePath(extension_path), Extension::INVALID, input,
136         Extension::STRICT_ERROR_CHECKS, &error));
137     EXPECT_EQ("", error);
138     return extension->id();
139   }
140  private:
141   NotificationService* service_;
142   BrowserThread ui_thread_;
143 };
144 
TEST_F(ExtensionsActivityMonitorTest,Basic)145 TEST_F(ExtensionsActivityMonitorTest, Basic) {
146   ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor();
147   BookmarkAPIEventGenerator generator;
148 
149   generator.NewEvent<RemoveBookmarkFunction>(kTestExtensionPath1,
150       new RemoveBookmarkFunction(), 1);
151   generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath1,
152       new MoveBookmarkFunction(), 1);
153   generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath1,
154       new UpdateBookmarkFunction(), 2);
155   generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
156       new CreateBookmarkFunction(), 3);
157   generator.NewEvent<SearchBookmarksFunction>(kTestExtensionPath1,
158       new SearchBookmarksFunction(), 5);
159   const uint32 writes_by_extension1 = 1 + 1 + 2 + 3;
160 
161   generator.NewEvent<RemoveTreeBookmarkFunction>(kTestExtensionPath2,
162       new RemoveTreeBookmarkFunction(), 8);
163   generator.NewEvent<GetBookmarkTreeFunction>(kTestExtensionPath2,
164       new GetBookmarkTreeFunction(), 13);
165   generator.NewEvent<GetBookmarkChildrenFunction>(kTestExtensionPath2,
166       new GetBookmarkChildrenFunction(), 21);
167   generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
168       new GetBookmarksFunction(), 33);
169   const uint32 writes_by_extension2 = 8;
170 
171   ExtensionsActivityMonitor::Records results;
172   monitor->GetAndClearRecords(&results);
173 
174   std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
175   std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);
176 
177   EXPECT_EQ(2U, results.size());
178   EXPECT_TRUE(results.end() != results.find(id1));
179   EXPECT_TRUE(results.end() != results.find(id2));
180   EXPECT_EQ(writes_by_extension1, results[id1].bookmark_write_count);
181   EXPECT_EQ(writes_by_extension2, results[id2].bookmark_write_count);
182 
183   ui_loop()->DeleteSoon(FROM_HERE, monitor);
184 }
185 
TEST_F(ExtensionsActivityMonitorTest,Put)186 TEST_F(ExtensionsActivityMonitorTest, Put) {
187   ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor();
188   BookmarkAPIEventGenerator generator;
189   std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
190   std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);
191 
192   generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
193       new CreateBookmarkFunction(), 5);
194   generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath2,
195       new MoveBookmarkFunction(), 8);
196 
197   ExtensionsActivityMonitor::Records results;
198   monitor->GetAndClearRecords(&results);
199 
200   EXPECT_EQ(2U, results.size());
201   EXPECT_EQ(5U, results[id1].bookmark_write_count);
202   EXPECT_EQ(8U, results[id2].bookmark_write_count);
203 
204   generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
205       new GetBookmarksFunction(), 3);
206   generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath2,
207       new UpdateBookmarkFunction(), 2);
208 
209   // Simulate a commit failure, which augments the active record set with the
210   // refugee records.
211   monitor->PutRecords(results);
212   ExtensionsActivityMonitor::Records new_records;
213   monitor->GetAndClearRecords(&new_records);
214 
215   EXPECT_EQ(2U, results.size());
216   EXPECT_EQ(id1, new_records[id1].extension_id);
217   EXPECT_EQ(id2, new_records[id2].extension_id);
218   EXPECT_EQ(5U, new_records[id1].bookmark_write_count);
219   EXPECT_EQ(8U + 2U, new_records[id2].bookmark_write_count);
220   ui_loop()->DeleteSoon(FROM_HERE, monitor);
221 }
222 
TEST_F(ExtensionsActivityMonitorTest,MultiGet)223 TEST_F(ExtensionsActivityMonitorTest, MultiGet) {
224   ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor();
225   BookmarkAPIEventGenerator generator;
226   std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
227 
228   generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
229       new CreateBookmarkFunction(), 5);
230 
231   ExtensionsActivityMonitor::Records results;
232   monitor->GetAndClearRecords(&results);
233 
234   EXPECT_EQ(1U, results.size());
235   EXPECT_EQ(5U, results[id1].bookmark_write_count);
236 
237   monitor->GetAndClearRecords(&results);
238   EXPECT_TRUE(results.empty());
239 
240   generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
241       new CreateBookmarkFunction(), 3);
242   monitor->GetAndClearRecords(&results);
243 
244   EXPECT_EQ(1U, results.size());
245   EXPECT_EQ(3U, results[id1].bookmark_write_count);
246 
247   ui_loop()->DeleteSoon(FROM_HERE, monitor);
248 }
249