Home | History | Annotate | Download | only in safe_browsing
      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 // This test uses the safebrowsing test server published at
      6 // http://code.google.com/p/google-safe-browsing/ to test the safebrowsing
      7 // protocol implemetation. Details of the safebrowsing testing flow is
      8 // documented at
      9 // http://code.google.com/p/google-safe-browsing/wiki/ProtocolTesting
     10 //
     11 // This test launches safebrowsing test server and issues several update
     12 // requests against that server. Each update would get different data and after
     13 // each update, the test will get a list of URLs from the test server to verify
     14 // its repository. The test will succeed only if all updates are performed and
     15 // URLs match what the server expected.
     16 
     17 #include <vector>
     18 
     19 #include "base/command_line.h"
     20 #include "base/environment.h"
     21 #include "base/path_service.h"
     22 #include "base/process_util.h"
     23 #include "base/string_number_conversions.h"
     24 #include "base/string_util.h"
     25 #include "base/string_split.h"
     26 #include "base/synchronization/lock.h"
     27 #include "base/threading/platform_thread.h"
     28 #include "base/time.h"
     29 #include "base/utf_string_conversions.h"
     30 #include "chrome/browser/browser_process.h"
     31 #include "chrome/browser/profiles/profile.h"
     32 #include "chrome/browser/safe_browsing/protocol_manager.h"
     33 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     34 #include "chrome/common/chrome_switches.h"
     35 #include "chrome/common/url_constants.h"
     36 #include "chrome/test/in_process_browser_test.h"
     37 #include "content/browser/browser_thread.h"
     38 #include "content/browser/renderer_host/resource_dispatcher_host.h"
     39 #include "base/test/test_timeouts.h"
     40 #include "chrome/test/ui_test_utils.h"
     41 #include "net/base/host_resolver.h"
     42 #include "net/base/load_flags.h"
     43 #include "net/base/net_log.h"
     44 #include "net/test/python_utils.h"
     45 #include "testing/gtest/include/gtest/gtest.h"
     46 
     47 namespace {
     48 
     49 const FilePath::CharType kDataFile[] = FILE_PATH_LITERAL("testing_input.dat");
     50 const char kUrlVerifyPath[] = "/safebrowsing/verify_urls";
     51 const char kDBVerifyPath[] = "/safebrowsing/verify_database";
     52 const char kDBResetPath[] = "/reset";
     53 const char kTestCompletePath[] = "/test_complete";
     54 
     55 struct PhishingUrl {
     56   std::string url;
     57   std::string list_name;
     58   bool is_phishing;
     59 };
     60 
     61 // Parses server response for verify_urls. The expected format is:
     62 //
     63 // first.random.url.com/   internal-test-shavar   yes
     64 // second.random.url.com/  internal-test-shavar   yes
     65 // ...
     66 bool ParsePhishingUrls(const std::string& data,
     67                        std::vector<PhishingUrl>* phishing_urls) {
     68   if (data.empty())
     69     return false;
     70 
     71   std::vector<std::string> urls;
     72   base::SplitString(data, '\n', &urls);
     73   for (size_t i = 0; i < urls.size(); ++i) {
     74     if (urls[i].empty())
     75       continue;
     76     PhishingUrl phishing_url;
     77     std::vector<std::string> record_parts;
     78     base::SplitString(urls[i], '\t', &record_parts);
     79     if (record_parts.size() != 3) {
     80       LOG(ERROR) << "Unexpected URL format in phishing URL list: "
     81                  << urls[i];
     82       return false;
     83     }
     84     phishing_url.url = std::string(chrome::kHttpScheme) +
     85         "://" + record_parts[0];
     86     phishing_url.list_name = record_parts[1];
     87     if (record_parts[2] == "yes") {
     88       phishing_url.is_phishing = true;
     89     } else if (record_parts[2] == "no") {
     90       phishing_url.is_phishing = false;
     91     } else {
     92       LOG(ERROR) << "Unrecognized expectation in " << urls[i]
     93                  << ": " << record_parts[2];
     94       return false;
     95     }
     96     phishing_urls->push_back(phishing_url);
     97   }
     98   return true;
     99 }
    100 
    101 }  // namespace
    102 
    103 class SafeBrowsingTestServer {
    104  public:
    105   explicit SafeBrowsingTestServer(const FilePath& datafile)
    106       : datafile_(datafile),
    107         server_handle_(base::kNullProcessHandle) {
    108   }
    109 
    110   ~SafeBrowsingTestServer() {
    111     EXPECT_EQ(base::kNullProcessHandle, server_handle_);
    112   }
    113 
    114   // Start the python server test suite.
    115   bool Start() {
    116     // Get path to python server script
    117     FilePath testserver_path;
    118     if (!PathService::Get(base::DIR_SOURCE_ROOT, &testserver_path)) {
    119       LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT";
    120       return false;
    121     }
    122     testserver_path = testserver_path
    123         .Append(FILE_PATH_LITERAL("third_party"))
    124         .Append(FILE_PATH_LITERAL("safe_browsing"))
    125         .Append(FILE_PATH_LITERAL("testing"));
    126     AppendToPythonPath(testserver_path);
    127     FilePath testserver = testserver_path.Append(
    128         FILE_PATH_LITERAL("safebrowsing_test_server.py"));
    129 
    130     FilePath pyproto_code_dir;
    131     if (!GetPyProtoPath(&pyproto_code_dir)) {
    132       LOG(ERROR) << "Failed to get generated python protobuf dir";
    133       return false;
    134     }
    135     AppendToPythonPath(pyproto_code_dir);
    136     pyproto_code_dir = pyproto_code_dir.Append(FILE_PATH_LITERAL("google"));
    137     AppendToPythonPath(pyproto_code_dir);
    138 
    139     FilePath python_runtime;
    140     EXPECT_TRUE(GetPythonRunTime(&python_runtime));
    141     CommandLine cmd_line(python_runtime);
    142     FilePath datafile = testserver_path.Append(datafile_);
    143     cmd_line.AppendArgPath(testserver);
    144     cmd_line.AppendSwitchASCII("port", StringPrintf("%d", kPort_));
    145     cmd_line.AppendSwitchPath("datafile", datafile);
    146 
    147     if (!base::LaunchApp(cmd_line, false, true, &server_handle_)) {
    148       LOG(ERROR) << "Failed to launch server: "
    149                  << cmd_line.command_line_string();
    150       return false;
    151     }
    152     return true;
    153   }
    154 
    155   // Stop the python server test suite.
    156   bool Stop() {
    157     if (server_handle_ == base::kNullProcessHandle)
    158       return true;
    159 
    160     // First check if the process has already terminated.
    161     if (!base::WaitForSingleProcess(server_handle_, 0) &&
    162         !base::KillProcess(server_handle_, 1, true)) {
    163       VLOG(1) << "Kill failed?";
    164       return false;
    165     }
    166 
    167     base::CloseProcessHandle(server_handle_);
    168     server_handle_ = base::kNullProcessHandle;
    169     VLOG(1) << "Stopped.";
    170     return true;
    171   }
    172 
    173   static const char* Host() {
    174     return kHost_;
    175   }
    176 
    177   static int Port() {
    178     return kPort_;
    179   }
    180 
    181  private:
    182   static const char kHost_[];
    183   static const int kPort_;
    184   FilePath datafile_;
    185   base::ProcessHandle server_handle_;
    186   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingTestServer);
    187 };
    188 
    189 const char SafeBrowsingTestServer::kHost_[] = "localhost";
    190 const int SafeBrowsingTestServer::kPort_ = 40102;
    191 
    192 // This starts the browser and keeps status of states related to SafeBrowsing.
    193 class SafeBrowsingServiceTest : public InProcessBrowserTest {
    194  public:
    195   SafeBrowsingServiceTest()
    196     : safe_browsing_service_(NULL),
    197       is_database_ready_(true),
    198       is_initial_request_(false),
    199       is_update_scheduled_(false),
    200       is_checked_url_in_db_(false),
    201       is_checked_url_safe_(false) {
    202   }
    203 
    204   virtual ~SafeBrowsingServiceTest() {
    205   }
    206 
    207   void UpdateSafeBrowsingStatus() {
    208     ASSERT_TRUE(safe_browsing_service_);
    209     base::AutoLock lock(update_status_mutex_);
    210     is_initial_request_ =
    211         safe_browsing_service_->protocol_manager_->is_initial_request();
    212     last_update_ = safe_browsing_service_->protocol_manager_->last_update();
    213     is_update_scheduled_ =
    214         safe_browsing_service_->protocol_manager_->update_timer_.IsRunning();
    215   }
    216 
    217   void ForceUpdate() {
    218     ASSERT_TRUE(safe_browsing_service_);
    219     safe_browsing_service_->protocol_manager_->ForceScheduleNextUpdate(0);
    220   }
    221 
    222   void CheckIsDatabaseReady() {
    223     base::AutoLock lock(update_status_mutex_);
    224     is_database_ready_ =
    225         !safe_browsing_service_->database_update_in_progress_;
    226   }
    227 
    228   void CheckUrl(SafeBrowsingService::Client* helper, const GURL& url) {
    229     ASSERT_TRUE(safe_browsing_service_);
    230     base::AutoLock lock(update_status_mutex_);
    231     if (safe_browsing_service_->CheckBrowseUrl(url, helper)) {
    232       is_checked_url_in_db_ = false;
    233       is_checked_url_safe_ = true;
    234     } else {
    235       // In this case, Safebrowsing service will fetch the full hash
    236       // from the server and examine that. Once it is done,
    237       // set_is_checked_url_safe() will be called via callback.
    238       is_checked_url_in_db_ = true;
    239     }
    240   }
    241 
    242   bool is_checked_url_in_db() {
    243     base::AutoLock l(update_status_mutex_);
    244     return is_checked_url_in_db_;
    245   }
    246 
    247   void set_is_checked_url_safe(bool safe) {
    248     base::AutoLock l(update_status_mutex_);
    249     is_checked_url_safe_ = safe;
    250   }
    251 
    252   bool is_checked_url_safe() {
    253     base::AutoLock l(update_status_mutex_);
    254     return is_checked_url_safe_;
    255   }
    256 
    257   bool is_database_ready() {
    258     base::AutoLock l(update_status_mutex_);
    259     return is_database_ready_;
    260   }
    261 
    262   bool is_initial_request() {
    263     base::AutoLock l(update_status_mutex_);
    264     return is_initial_request_;
    265   }
    266 
    267   base::Time last_update() {
    268     base::AutoLock l(update_status_mutex_);
    269     return last_update_;
    270   }
    271 
    272   bool is_update_scheduled() {
    273     base::AutoLock l(update_status_mutex_);
    274     return is_update_scheduled_;
    275   }
    276 
    277   MessageLoop* SafeBrowsingMessageLoop() {
    278     return safe_browsing_service_->safe_browsing_thread_->message_loop();
    279   }
    280 
    281  protected:
    282   bool InitSafeBrowsingService() {
    283     safe_browsing_service_ =
    284         g_browser_process->resource_dispatcher_host()->safe_browsing_service();
    285     return safe_browsing_service_ != NULL;
    286   }
    287 
    288   virtual void SetUpCommandLine(CommandLine* command_line) {
    289     // Makes sure the auto update is not triggered. This test will force the
    290     // update when needed.
    291     command_line->AppendSwitch(switches::kSbDisableAutoUpdate);
    292 
    293     // This test uses loopback. No need to use IPv6 especially it makes
    294     // local requests slow on Windows trybot when ipv6 local address [::1]
    295     // is not setup.
    296     command_line->AppendSwitch(switches::kDisableIPv6);
    297 
    298     // TODO(lzheng): The test server does not understand download related
    299     // requests. We need to fix the server.
    300     command_line->AppendSwitch(switches::kSbDisableDownloadProtection);
    301 
    302     // In this test, we fetch SafeBrowsing data and Mac key from the same
    303     // server. Although in real production, they are served from different
    304     // servers.
    305     std::string url_prefix =
    306         StringPrintf("http://%s:%d/safebrowsing",
    307                      SafeBrowsingTestServer::Host(),
    308                      SafeBrowsingTestServer::Port());
    309     command_line->AppendSwitchASCII(switches::kSbInfoURLPrefix, url_prefix);
    310     command_line->AppendSwitchASCII(switches::kSbMacKeyURLPrefix, url_prefix);
    311   }
    312 
    313   void SetTestStep(int step) {
    314     std::string test_step = StringPrintf("test_step=%d", step);
    315     safe_browsing_service_->protocol_manager_->set_additional_query(test_step);
    316   }
    317 
    318  private:
    319   SafeBrowsingService* safe_browsing_service_;
    320 
    321   // Protects all variables below since they are read on UI thread
    322   // but updated on IO thread or safebrowsing thread.
    323   base::Lock update_status_mutex_;
    324 
    325   // States associated with safebrowsing service updates.
    326   bool is_database_ready_;
    327   bool is_initial_request_;
    328   base::Time last_update_;
    329   bool is_update_scheduled_;
    330   // Indicates if there is a match between a URL's prefix and safebrowsing
    331   // database (thus potentially it is a phishing URL).
    332   bool is_checked_url_in_db_;
    333   // True if last verified URL is not a phishing URL and thus it is safe.
    334   bool is_checked_url_safe_;
    335 
    336   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTest);
    337 };
    338 
    339 // A ref counted helper class that handles callbacks between IO thread and UI
    340 // thread.
    341 class SafeBrowsingServiceTestHelper
    342     : public base::RefCountedThreadSafe<SafeBrowsingServiceTestHelper>,
    343       public SafeBrowsingService::Client,
    344       public URLFetcher::Delegate {
    345  public:
    346   explicit SafeBrowsingServiceTestHelper(
    347       SafeBrowsingServiceTest* safe_browsing_test)
    348       : safe_browsing_test_(safe_browsing_test),
    349         response_status_(net::URLRequestStatus::FAILED) {
    350   }
    351 
    352   // Callbacks for SafeBrowsingService::Client.
    353   virtual void OnBrowseUrlCheckResult(
    354       const GURL& url, SafeBrowsingService::UrlCheckResult result) {
    355     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    356     EXPECT_TRUE(safe_browsing_test_->is_checked_url_in_db());
    357     safe_browsing_test_->set_is_checked_url_safe(
    358         result == SafeBrowsingService::SAFE);
    359     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    360                             NewRunnableMethod(this,
    361                             &SafeBrowsingServiceTestHelper::OnCheckUrlDone));
    362   }
    363   virtual void OnDownloadUrlCheckResult(
    364       const std::vector<GURL>& url_chain,
    365       SafeBrowsingService::UrlCheckResult result) {
    366     // TODO(lzheng): Add test for DownloadUrl.
    367   }
    368 
    369   virtual void OnBlockingPageComplete(bool proceed) {
    370     NOTREACHED() << "Not implemented.";
    371   }
    372 
    373   // Functions and callbacks to start the safebrowsing database update.
    374   void ForceUpdate() {
    375     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
    376         NewRunnableMethod(this,
    377         &SafeBrowsingServiceTestHelper::ForceUpdateInIOThread));
    378     // Will continue after OnForceUpdateDone().
    379     ui_test_utils::RunMessageLoop();
    380   }
    381   void ForceUpdateInIOThread() {
    382     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    383     safe_browsing_test_->ForceUpdate();
    384     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    385         NewRunnableMethod(this,
    386         &SafeBrowsingServiceTestHelper::OnForceUpdateDone));
    387   }
    388   void OnForceUpdateDone() {
    389     StopUILoop();
    390   }
    391 
    392   // Functions and callbacks related to CheckUrl. These are used to verify
    393   // phishing URLs.
    394   void CheckUrl(const GURL& url) {
    395     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, NewRunnableMethod(
    396         this, &SafeBrowsingServiceTestHelper::CheckUrlOnIOThread, url));
    397     ui_test_utils::RunMessageLoop();
    398   }
    399   void CheckUrlOnIOThread(const GURL& url) {
    400     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    401     safe_browsing_test_->CheckUrl(this, url);
    402     if (!safe_browsing_test_->is_checked_url_in_db()) {
    403       // Ends the checking since this URL's prefix is not in database.
    404       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
    405           this, &SafeBrowsingServiceTestHelper::OnCheckUrlDone));
    406     }
    407     // Otherwise, OnCheckUrlDone is called in OnUrlCheckResult since
    408     // safebrowsing service further fetches hashes from safebrowsing server.
    409   }
    410 
    411   void OnCheckUrlDone() {
    412     StopUILoop();
    413   }
    414 
    415   // Updates status from IO Thread.
    416   void CheckStatusOnIOThread() {
    417     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    418     safe_browsing_test_->UpdateSafeBrowsingStatus();
    419     safe_browsing_test_->SafeBrowsingMessageLoop()->PostTask(
    420         FROM_HERE, NewRunnableMethod(this,
    421         &SafeBrowsingServiceTestHelper::CheckIsDatabaseReady));
    422   }
    423 
    424   // Checks status in SafeBrowsing Thread.
    425   void CheckIsDatabaseReady() {
    426     EXPECT_EQ(MessageLoop::current(),
    427               safe_browsing_test_->SafeBrowsingMessageLoop());
    428     safe_browsing_test_->CheckIsDatabaseReady();
    429     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
    430         this, &SafeBrowsingServiceTestHelper::OnWaitForStatusUpdateDone));
    431   }
    432 
    433   void OnWaitForStatusUpdateDone() {
    434     StopUILoop();
    435   }
    436 
    437   // Wait for a given period to get safebrowsing status updated.
    438   void WaitForStatusUpdate(int64 wait_time_msec) {
    439     BrowserThread::PostDelayedTask(
    440         BrowserThread::IO,
    441         FROM_HERE,
    442         NewRunnableMethod(this,
    443             &SafeBrowsingServiceTestHelper::CheckStatusOnIOThread),
    444         wait_time_msec);
    445     // Will continue after OnWaitForStatusUpdateDone().
    446     ui_test_utils::RunMessageLoop();
    447   }
    448 
    449   void WaitTillServerReady(const char* host, int port) {
    450     response_status_ = net::URLRequestStatus::FAILED;
    451     GURL url(StringPrintf("http://%s:%d%s?test_step=0",
    452                           host, port, kDBResetPath));
    453     // TODO(lzheng): We should have a way to reliably tell when a server is
    454     // ready so we could get rid of the Sleep and retry loop.
    455     while (true) {
    456       if (FetchUrl(url) == net::URLRequestStatus::SUCCESS)
    457         break;
    458       // Wait and try again if last fetch was failed. The loop will hit the
    459       // timeout in OutOfProcTestRunner if the fetch can not get success
    460       // response.
    461       base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
    462     }
    463   }
    464 
    465   // Calls test server to fetch database for verification.
    466   net::URLRequestStatus::Status FetchDBToVerify(const char* host, int port,
    467                                                 int test_step) {
    468     // TODO(lzheng): Remove chunk_type=add once it is not needed by the server.
    469     GURL url(StringPrintf("http://%s:%d%s?"
    470                           "client=chromium&appver=1.0&pver=2.2&test_step=%d&"
    471                           "chunk_type=add",
    472                           host, port, kDBVerifyPath, test_step));
    473     return FetchUrl(url);
    474   }
    475 
    476   // Calls test server to fetch URLs for verification.
    477   net::URLRequestStatus::Status FetchUrlsToVerify(const char* host, int port,
    478                                                   int test_step) {
    479     GURL url(StringPrintf("http://%s:%d%s?"
    480                           "client=chromium&appver=1.0&pver=2.2&test_step=%d",
    481                           host, port, kUrlVerifyPath, test_step));
    482     return FetchUrl(url);
    483   }
    484 
    485   // Calls test server to check if test data is done. E.g.: if there is a
    486   // bad URL that server expects test to fetch full hash but the test didn't,
    487   // this verification will fail.
    488   net::URLRequestStatus::Status VerifyTestComplete(const char* host, int port,
    489                                                    int test_step) {
    490     GURL url(StringPrintf("http://%s:%d%s?test_step=%d",
    491                           host, port, kTestCompletePath, test_step));
    492     return FetchUrl(url);
    493   }
    494 
    495   // Callback for URLFetcher.
    496   virtual void OnURLFetchComplete(const URLFetcher* source,
    497                                   const GURL& url,
    498                                   const net::URLRequestStatus& status,
    499                                   int response_code,
    500                                   const ResponseCookies& cookies,
    501                                   const std::string& data) {
    502     response_data_ = data;
    503     response_status_ = status.status();
    504     StopUILoop();
    505   }
    506 
    507   const std::string& response_data() {
    508     return response_data_;
    509   }
    510 
    511  private:
    512   // Stops UI loop after desired status is updated.
    513   void StopUILoop() {
    514     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
    515     MessageLoopForUI::current()->Quit();
    516   }
    517 
    518   // Fetch a URL. If message_loop_started is true, starts the message loop
    519   // so the caller could wait till OnURLFetchComplete is called.
    520   net::URLRequestStatus::Status FetchUrl(const GURL& url) {
    521     url_fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
    522     url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE);
    523     url_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
    524     url_fetcher_->Start();
    525     ui_test_utils::RunMessageLoop();
    526     return response_status_;
    527   }
    528 
    529   base::OneShotTimer<SafeBrowsingServiceTestHelper> check_update_timer_;
    530   SafeBrowsingServiceTest* safe_browsing_test_;
    531   scoped_ptr<URLFetcher> url_fetcher_;
    532   std::string response_data_;
    533   net::URLRequestStatus::Status response_status_;
    534   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTestHelper);
    535 };
    536 
    537 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, SafeBrowsingSystemTest) {
    538   LOG(INFO) << "Start test";
    539   const char* server_host = SafeBrowsingTestServer::Host();
    540   int server_port = SafeBrowsingTestServer::Port();
    541   ASSERT_TRUE(InitSafeBrowsingService());
    542 
    543   scoped_refptr<SafeBrowsingServiceTestHelper> safe_browsing_helper(
    544       new SafeBrowsingServiceTestHelper(this));
    545   int last_step = 0;
    546   FilePath datafile_path = FilePath(kDataFile);
    547   SafeBrowsingTestServer test_server(datafile_path);
    548   ASSERT_TRUE(test_server.Start());
    549 
    550   // Make sure the server is running.
    551   safe_browsing_helper->WaitTillServerReady(server_host, server_port);
    552 
    553   // Waits and makes sure safebrowsing update is not happening.
    554   // The wait will stop once OnWaitForStatusUpdateDone in
    555   // safe_browsing_helper is called and status from safe_browsing_service_
    556   // is checked.
    557   safe_browsing_helper->WaitForStatusUpdate(0);
    558   EXPECT_TRUE(is_database_ready());
    559   EXPECT_TRUE(is_initial_request());
    560   EXPECT_FALSE(is_update_scheduled());
    561   EXPECT_TRUE(last_update().is_null());
    562   // Starts updates. After each update, the test will fetch a list of URLs with
    563   // expected results to verify with safebrowsing service. If there is no error,
    564   // the test moves on to the next step to get more update chunks.
    565   // This repeats till there is no update data.
    566   for (int step = 1;; step++) {
    567     // Every step should be a fresh start.
    568     SCOPED_TRACE(StringPrintf("step=%d", step));
    569     EXPECT_TRUE(is_database_ready());
    570     EXPECT_FALSE(is_update_scheduled());
    571 
    572     // Starts safebrowsing update on IO thread. Waits till scheduled
    573     // update finishes. Stops waiting after kMaxWaitSecPerStep if the update
    574     // could not finish.
    575     base::Time now = base::Time::Now();
    576     SetTestStep(step);
    577     safe_browsing_helper->ForceUpdate();
    578 
    579     do {
    580       // Periodically pull the status.
    581       safe_browsing_helper->WaitForStatusUpdate(
    582           TestTimeouts::action_timeout_ms());
    583     } while (is_update_scheduled() || is_initial_request() ||
    584              !is_database_ready());
    585 
    586 
    587     if (last_update() < now) {
    588       // This means no data available anymore.
    589       break;
    590     }
    591 
    592     // Fetches URLs to verify and waits till server responses with data.
    593     EXPECT_EQ(net::URLRequestStatus::SUCCESS,
    594               safe_browsing_helper->FetchUrlsToVerify(server_host,
    595                                                       server_port,
    596                                                       step));
    597 
    598     std::vector<PhishingUrl> phishing_urls;
    599     EXPECT_TRUE(ParsePhishingUrls(safe_browsing_helper->response_data(),
    600                                   &phishing_urls));
    601     EXPECT_GT(phishing_urls.size(), 0U);
    602     for (size_t j = 0; j < phishing_urls.size(); ++j) {
    603       // Verifes with server if a URL is a phishing URL and waits till server
    604       // responses.
    605       safe_browsing_helper->CheckUrl(GURL(phishing_urls[j].url));
    606       if (phishing_urls[j].is_phishing) {
    607         EXPECT_TRUE(is_checked_url_in_db())
    608             << phishing_urls[j].url
    609             << " is_phishing: " << phishing_urls[j].is_phishing
    610             << " test step: " << step;
    611         EXPECT_FALSE(is_checked_url_safe())
    612             << phishing_urls[j].url
    613             << " is_phishing: " << phishing_urls[j].is_phishing
    614             << " test step: " << step;
    615       } else {
    616         EXPECT_TRUE(is_checked_url_safe())
    617             << phishing_urls[j].url
    618             << " is_phishing: " << phishing_urls[j].is_phishing
    619             << " test step: " << step;
    620       }
    621     }
    622     // TODO(lzheng): We should verify the fetched database with local
    623     // database to make sure they match.
    624     EXPECT_EQ(net::URLRequestStatus::SUCCESS,
    625               safe_browsing_helper->FetchDBToVerify(server_host,
    626                                                     server_port,
    627                                                     step));
    628     EXPECT_GT(safe_browsing_helper->response_data().size(), 0U);
    629     last_step = step;
    630   }
    631 
    632   // Verifies with server if test is done and waits till server responses.
    633   EXPECT_EQ(net::URLRequestStatus::SUCCESS,
    634             safe_browsing_helper->VerifyTestComplete(server_host,
    635                                                      server_port,
    636                                                      last_step));
    637   EXPECT_EQ("yes", safe_browsing_helper->response_data());
    638   test_server.Stop();
    639 }
    640