Home | History | Annotate | Download | only in search_engines
      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/search_engines/template_url_model_test_util.h"
      6 
      7 #include "base/memory/scoped_temp_dir.h"
      8 #include "base/message_loop.h"
      9 #include "base/path_service.h"
     10 #include "base/threading/thread.h"
     11 #include "chrome/browser/search_engines/template_url.h"
     12 #include "chrome/browser/search_engines/template_url_model.h"
     13 #include "chrome/test/testing_profile.h"
     14 #include "content/common/notification_service.h"
     15 #include "content/common/notification_type.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace {
     19 
     20 // A Task used to coordinate when the database has finished processing
     21 // requests. See note in BlockTillServiceProcessesRequests for details.
     22 //
     23 // When Run() schedules a QuitTask on the message loop it was created with.
     24 class QuitTask2 : public Task {
     25  public:
     26   QuitTask2() : main_loop_(MessageLoop::current()) {}
     27 
     28   virtual void Run() {
     29     main_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
     30   }
     31 
     32  private:
     33   MessageLoop* main_loop_;
     34 };
     35 
     36 // Blocks the caller until thread has finished servicing all pending
     37 // requests.
     38 static void WaitForThreadToProcessRequests(BrowserThread::ID identifier) {
     39   // Schedule a task on the thread that is processed after all
     40   // pending requests on the thread.
     41   BrowserThread::PostTask(identifier, FROM_HERE, new QuitTask2());
     42   // Run the current message loop. QuitTask2, when run, invokes Quit,
     43   // which unblocks this.
     44   MessageLoop::current()->Run();
     45 }
     46 
     47 }  // namespace
     48 
     49 // Subclass the TestingProfile so that it can return a WebDataService.
     50 class TemplateURLModelTestingProfile : public TestingProfile {
     51  public:
     52   TemplateURLModelTestingProfile()
     53       : TestingProfile(),
     54         db_thread_(BrowserThread::DB),
     55         io_thread_(BrowserThread::IO) {
     56   }
     57 
     58   void SetUp();
     59   void TearDown();
     60 
     61   // Starts the I/O thread. This isn't done automatically because not every test
     62   // needs this.
     63   void StartIOThread() {
     64     base::Thread::Options options;
     65     options.message_loop_type = MessageLoop::TYPE_IO;
     66     io_thread_.StartWithOptions(options);
     67   }
     68 
     69   virtual WebDataService* GetWebDataService(ServiceAccessType access) {
     70     return service_.get();
     71   }
     72 
     73  private:
     74   scoped_refptr<WebDataService> service_;
     75   ScopedTempDir temp_dir_;
     76   BrowserThread db_thread_;
     77   BrowserThread io_thread_;
     78 };
     79 
     80 // Trivial subclass of TemplateURLModel that records the last invocation of
     81 // SetKeywordSearchTermsForURL.
     82 class TestingTemplateURLModel : public TemplateURLModel {
     83  public:
     84   explicit TestingTemplateURLModel(Profile* profile)
     85       : TemplateURLModel(profile) {
     86   }
     87 
     88   string16 GetAndClearSearchTerm() {
     89     string16 search_term;
     90     search_term.swap(search_term_);
     91     return search_term;
     92   }
     93 
     94  protected:
     95   virtual void SetKeywordSearchTermsForURL(const TemplateURL* t_url,
     96                                            const GURL& url,
     97                                            const string16& term) {
     98     search_term_ = term;
     99   }
    100 
    101  private:
    102   string16 search_term_;
    103 
    104   DISALLOW_COPY_AND_ASSIGN(TestingTemplateURLModel);
    105 };
    106 
    107 void TemplateURLModelTestingProfile::SetUp() {
    108   db_thread_.Start();
    109 
    110   // Make unique temp directory.
    111   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    112 
    113   FilePath path = temp_dir_.path().AppendASCII("TestDataService.db");
    114   service_ = new WebDataService;
    115   ASSERT_TRUE(service_->InitWithPath(path));
    116 }
    117 
    118 void TemplateURLModelTestingProfile::TearDown() {
    119   // Clear the request context so it will get deleted. This should be done
    120   // before shutting down the I/O thread to avoid memory leaks.
    121   ResetRequestContext();
    122 
    123   // Wait for the delete of the request context to happen.
    124   if (io_thread_.IsRunning())
    125     TemplateURLModelTestUtil::BlockTillIOThreadProcessesRequests();
    126 
    127   // The I/O thread must be shutdown before the DB thread.
    128   io_thread_.Stop();
    129 
    130   // Clean up the test directory.
    131   if (service_.get())
    132     service_->Shutdown();
    133   // Note that we must ensure the DB thread is stopped after WDS
    134   // shutdown (so it can commit pending transactions) but before
    135   // deleting the test profile directory, otherwise we may not be
    136   // able to delete it due to an open transaction.
    137   db_thread_.Stop();
    138 }
    139 
    140 TemplateURLModelTestUtil::TemplateURLModelTestUtil()
    141     : ui_thread_(BrowserThread::UI, &message_loop_),
    142       changed_count_(0) {
    143 }
    144 
    145 TemplateURLModelTestUtil::~TemplateURLModelTestUtil() {
    146 }
    147 
    148 void TemplateURLModelTestUtil::SetUp() {
    149   profile_.reset(new TemplateURLModelTestingProfile());
    150   profile_->SetUp();
    151   profile_->SetTemplateURLModel(new TestingTemplateURLModel(profile_.get()));
    152   profile_->GetTemplateURLModel()->AddObserver(this);
    153 }
    154 
    155 void TemplateURLModelTestUtil::TearDown() {
    156   if (profile_.get()) {
    157     profile_->TearDown();
    158     profile_.reset();
    159   }
    160   TemplateURLRef::SetGoogleBaseURL(NULL);
    161 
    162   // Flush the message loop to make Purify happy.
    163   message_loop_.RunAllPending();
    164 }
    165 
    166 void TemplateURLModelTestUtil::OnTemplateURLModelChanged() {
    167   changed_count_++;
    168 }
    169 
    170 int TemplateURLModelTestUtil::GetObserverCount() {
    171   return changed_count_;
    172 }
    173 
    174 void TemplateURLModelTestUtil::ResetObserverCount() {
    175   changed_count_ = 0;
    176 }
    177 
    178 void TemplateURLModelTestUtil::BlockTillServiceProcessesRequests() {
    179   WaitForThreadToProcessRequests(BrowserThread::DB);
    180 }
    181 
    182 void TemplateURLModelTestUtil::BlockTillIOThreadProcessesRequests() {
    183   WaitForThreadToProcessRequests(BrowserThread::IO);
    184 }
    185 
    186 void TemplateURLModelTestUtil::VerifyLoad() {
    187   ASSERT_FALSE(model()->loaded());
    188   model()->Load();
    189   BlockTillServiceProcessesRequests();
    190   EXPECT_EQ(1, GetObserverCount());
    191   ResetObserverCount();
    192 }
    193 
    194 void TemplateURLModelTestUtil::ChangeModelToLoadState() {
    195   model()->ChangeToLoadedState();
    196   // Initialize the web data service so that the database gets updated with
    197   // any changes made.
    198   model()->service_ = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
    199 }
    200 
    201 void TemplateURLModelTestUtil::ClearModel() {
    202   profile_->SetTemplateURLModel(NULL);
    203 }
    204 
    205 void TemplateURLModelTestUtil::ResetModel(bool verify_load) {
    206   profile_->SetTemplateURLModel(new TestingTemplateURLModel(profile_.get()));
    207   model()->AddObserver(this);
    208   changed_count_ = 0;
    209   if (verify_load)
    210     VerifyLoad();
    211 }
    212 
    213 string16 TemplateURLModelTestUtil::GetAndClearSearchTerm() {
    214   return
    215       static_cast<TestingTemplateURLModel*>(model())->GetAndClearSearchTerm();
    216 }
    217 
    218 void TemplateURLModelTestUtil::SetGoogleBaseURL(
    219     const std::string& base_url) const {
    220   TemplateURLRef::SetGoogleBaseURL(new std::string(base_url));
    221   NotificationService::current()->Notify(NotificationType::GOOGLE_URL_UPDATED,
    222                                          NotificationService::AllSources(),
    223                                          NotificationService::NoDetails());
    224 }
    225 
    226 WebDataService* TemplateURLModelTestUtil::GetWebDataService() {
    227   return profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
    228 }
    229 
    230 TemplateURLModel* TemplateURLModelTestUtil::model() const {
    231   return profile_->GetTemplateURLModel();
    232 }
    233 
    234 TestingProfile* TemplateURLModelTestUtil::profile() const {
    235   return profile_.get();
    236 }
    237 
    238 void TemplateURLModelTestUtil::StartIOThread() {
    239   profile_->StartIOThread();
    240 }
    241