Home | History | Annotate | Download | only in util
      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:
     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 
     64 class 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,
     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:
     93   DoUIThreadSetupTask(NotificationService** service,
     94                       base::WaitableEvent* done)
     95       : service_(service), signal_when_done_(done) {}
     96   virtual ~DoUIThreadSetupTask() {}
     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:
    109   ExtensionsActivityMonitorTest() : service_(NULL),
    110       ui_thread_(BrowserThread::UI) { }
    111   virtual ~ExtensionsActivityMonitorTest() {}
    112 
    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 
    121   virtual void TearDown() {
    122     ui_thread_.message_loop()->DeleteSoon(FROM_HERE, service_);
    123     ui_thread_.Stop();
    124   }
    125 
    126   MessageLoop* ui_loop() { return ui_thread_.message_loop(); }
    127 
    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 
    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 
    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 
    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