extensions_activity_monitor_unittest.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2009 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/browser_thread.h"
12#include "chrome/browser/extensions/extension_bookmarks_module.h"
13#include "chrome/common/extensions/extension.h"
14#include "chrome/common/extensions/extension_constants.h"
15#include "chrome/common/notification_service.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18using browser_sync::ExtensionsActivityMonitor;
19namespace keys = extension_manifest_keys;
20
21namespace {
22
23const 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
30const 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
37const char* kTestExtensionVersion = "1.0.0.0";
38const char* kTestExtensionName = "foo extension";
39
40template <class FunctionType>
41class BookmarkAPIEventTask : public Task {
42 public:
43  BookmarkAPIEventTask(FunctionType* t, Extension* e, size_t repeats,
44                       base::WaitableEvent* done) :
45       extension_(e), function_(t), repeats_(repeats), done_(done) {}
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
64class BookmarkAPIEventGenerator {
65 public:
66  BookmarkAPIEventGenerator() {}
67  virtual ~BookmarkAPIEventGenerator() {}
68  template <class T>
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, false, &error));
77    bookmarks_function->set_name(T::function_name());
78    base::WaitableEvent done_event(false, false);
79    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
80        new BookmarkAPIEventTask<T>(bookmarks_function, extension,
81                                    repeats, &done_event));
82    done_event.Wait();
83  }
84
85 private:
86  DISALLOW_COPY_AND_ASSIGN(BookmarkAPIEventGenerator);
87};
88}  // namespace
89
90class DoUIThreadSetupTask : public Task {
91 public:
92  DoUIThreadSetupTask(NotificationService** service,
93                      base::WaitableEvent* done)
94      : service_(service), signal_when_done_(done) {}
95  virtual ~DoUIThreadSetupTask() {}
96  virtual void Run() {
97    *service_ = new NotificationService();
98    signal_when_done_->Signal();
99  }
100 private:
101  NotificationService** service_;
102  base::WaitableEvent* signal_when_done_;
103  DISALLOW_COPY_AND_ASSIGN(DoUIThreadSetupTask);
104};
105
106class ExtensionsActivityMonitorTest : public testing::Test {
107 public:
108  ExtensionsActivityMonitorTest() : service_(NULL),
109      ui_thread_(BrowserThread::UI) { }
110  virtual ~ExtensionsActivityMonitorTest() {}
111
112  virtual void SetUp() {
113    ui_thread_.Start();
114    base::WaitableEvent service_created(false, false);
115    ui_thread_.message_loop()->PostTask(FROM_HERE,
116        new DoUIThreadSetupTask(&service_, &service_created));
117    service_created.Wait();
118  }
119
120  virtual void TearDown() {
121    ui_thread_.message_loop()->DeleteSoon(FROM_HERE, service_);
122    ui_thread_.Stop();
123  }
124
125  MessageLoop* ui_loop() { return ui_thread_.message_loop(); }
126
127  static std::string GetExtensionIdForPath(
128      const FilePath::StringType& extension_path) {
129    std::string error;
130    DictionaryValue input;
131    input.SetString(keys::kVersion, kTestExtensionVersion);
132    input.SetString(keys::kName, kTestExtensionName);
133    scoped_refptr<Extension> extension(Extension::Create(
134        FilePath(extension_path), Extension::INVALID, input, false, &error));
135    EXPECT_EQ("", error);
136    return extension->id();
137  }
138 private:
139  NotificationService* service_;
140  BrowserThread ui_thread_;
141};
142
143TEST_F(ExtensionsActivityMonitorTest, Basic) {
144  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor();
145  BookmarkAPIEventGenerator generator;
146
147  generator.NewEvent<RemoveBookmarkFunction>(kTestExtensionPath1,
148      new RemoveBookmarkFunction(), 1);
149  generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath1,
150      new MoveBookmarkFunction(), 1);
151  generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath1,
152      new UpdateBookmarkFunction(), 2);
153  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
154      new CreateBookmarkFunction(), 3);
155  generator.NewEvent<SearchBookmarksFunction>(kTestExtensionPath1,
156      new SearchBookmarksFunction(), 5);
157  const uint32 writes_by_extension1 = 1 + 1 + 2 + 3;
158
159  generator.NewEvent<RemoveTreeBookmarkFunction>(kTestExtensionPath2,
160      new RemoveTreeBookmarkFunction(), 8);
161  generator.NewEvent<GetBookmarkTreeFunction>(kTestExtensionPath2,
162      new GetBookmarkTreeFunction(), 13);
163  generator.NewEvent<GetBookmarkChildrenFunction>(kTestExtensionPath2,
164      new GetBookmarkChildrenFunction(), 21);
165  generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
166      new GetBookmarksFunction(), 33);
167  const uint32 writes_by_extension2 = 8;
168
169  ExtensionsActivityMonitor::Records results;
170  monitor->GetAndClearRecords(&results);
171
172  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
173  std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);
174
175  EXPECT_EQ(2U, results.size());
176  EXPECT_TRUE(results.end() != results.find(id1));
177  EXPECT_TRUE(results.end() != results.find(id2));
178  EXPECT_EQ(writes_by_extension1, results[id1].bookmark_write_count);
179  EXPECT_EQ(writes_by_extension2, results[id2].bookmark_write_count);
180
181  ui_loop()->DeleteSoon(FROM_HERE, monitor);
182}
183
184TEST_F(ExtensionsActivityMonitorTest, Put) {
185  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor();
186  BookmarkAPIEventGenerator generator;
187  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
188  std::string id2 = GetExtensionIdForPath(kTestExtensionPath2);
189
190  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
191      new CreateBookmarkFunction(), 5);
192  generator.NewEvent<MoveBookmarkFunction>(kTestExtensionPath2,
193      new MoveBookmarkFunction(), 8);
194
195  ExtensionsActivityMonitor::Records results;
196  monitor->GetAndClearRecords(&results);
197
198  EXPECT_EQ(2U, results.size());
199  EXPECT_EQ(5U, results[id1].bookmark_write_count);
200  EXPECT_EQ(8U, results[id2].bookmark_write_count);
201
202  generator.NewEvent<GetBookmarksFunction>(kTestExtensionPath2,
203      new GetBookmarksFunction(), 3);
204  generator.NewEvent<UpdateBookmarkFunction>(kTestExtensionPath2,
205      new UpdateBookmarkFunction(), 2);
206
207  // Simulate a commit failure, which augments the active record set with the
208  // refugee records.
209  monitor->PutRecords(results);
210  ExtensionsActivityMonitor::Records new_records;
211  monitor->GetAndClearRecords(&new_records);
212
213  EXPECT_EQ(2U, results.size());
214  EXPECT_EQ(id1, new_records[id1].extension_id);
215  EXPECT_EQ(id2, new_records[id2].extension_id);
216  EXPECT_EQ(5U, new_records[id1].bookmark_write_count);
217  EXPECT_EQ(8U + 2U, new_records[id2].bookmark_write_count);
218  ui_loop()->DeleteSoon(FROM_HERE, monitor);
219}
220
221TEST_F(ExtensionsActivityMonitorTest, MultiGet) {
222  ExtensionsActivityMonitor* monitor = new ExtensionsActivityMonitor();
223  BookmarkAPIEventGenerator generator;
224  std::string id1 = GetExtensionIdForPath(kTestExtensionPath1);
225
226  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
227      new CreateBookmarkFunction(), 5);
228
229  ExtensionsActivityMonitor::Records results;
230  monitor->GetAndClearRecords(&results);
231
232  EXPECT_EQ(1U, results.size());
233  EXPECT_EQ(5U, results[id1].bookmark_write_count);
234
235  monitor->GetAndClearRecords(&results);
236  EXPECT_TRUE(results.empty());
237
238  generator.NewEvent<CreateBookmarkFunction>(kTestExtensionPath1,
239      new CreateBookmarkFunction(), 3);
240  monitor->GetAndClearRecords(&results);
241
242  EXPECT_EQ(1U, results.size());
243  EXPECT_EQ(3U, results[id1].bookmark_write_count);
244
245  ui_loop()->DeleteSoon(FROM_HERE, monitor);
246}
247