• 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 // 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 // ...
ParsePhishingUrls(const std::string & data,std::vector<PhishingUrl> * phishing_urls)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:
SafeBrowsingTestServer(const FilePath & datafile)105   explicit SafeBrowsingTestServer(const FilePath& datafile)
106       : datafile_(datafile),
107         server_handle_(base::kNullProcessHandle) {
108   }
109 
~SafeBrowsingTestServer()110   ~SafeBrowsingTestServer() {
111     EXPECT_EQ(base::kNullProcessHandle, server_handle_);
112   }
113 
114   // Start the python server test suite.
Start()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.
Stop()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 
Host()173   static const char* Host() {
174     return kHost_;
175   }
176 
Port()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:
SafeBrowsingServiceTest()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 
~SafeBrowsingServiceTest()204   virtual ~SafeBrowsingServiceTest() {
205   }
206 
UpdateSafeBrowsingStatus()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 
ForceUpdate()217   void ForceUpdate() {
218     ASSERT_TRUE(safe_browsing_service_);
219     safe_browsing_service_->protocol_manager_->ForceScheduleNextUpdate(0);
220   }
221 
CheckIsDatabaseReady()222   void CheckIsDatabaseReady() {
223     base::AutoLock lock(update_status_mutex_);
224     is_database_ready_ =
225         !safe_browsing_service_->database_update_in_progress_;
226   }
227 
CheckUrl(SafeBrowsingService::Client * helper,const GURL & url)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 
is_checked_url_in_db()242   bool is_checked_url_in_db() {
243     base::AutoLock l(update_status_mutex_);
244     return is_checked_url_in_db_;
245   }
246 
set_is_checked_url_safe(bool safe)247   void set_is_checked_url_safe(bool safe) {
248     base::AutoLock l(update_status_mutex_);
249     is_checked_url_safe_ = safe;
250   }
251 
is_checked_url_safe()252   bool is_checked_url_safe() {
253     base::AutoLock l(update_status_mutex_);
254     return is_checked_url_safe_;
255   }
256 
is_database_ready()257   bool is_database_ready() {
258     base::AutoLock l(update_status_mutex_);
259     return is_database_ready_;
260   }
261 
is_initial_request()262   bool is_initial_request() {
263     base::AutoLock l(update_status_mutex_);
264     return is_initial_request_;
265   }
266 
last_update()267   base::Time last_update() {
268     base::AutoLock l(update_status_mutex_);
269     return last_update_;
270   }
271 
is_update_scheduled()272   bool is_update_scheduled() {
273     base::AutoLock l(update_status_mutex_);
274     return is_update_scheduled_;
275   }
276 
SafeBrowsingMessageLoop()277   MessageLoop* SafeBrowsingMessageLoop() {
278     return safe_browsing_service_->safe_browsing_thread_->message_loop();
279   }
280 
281  protected:
InitSafeBrowsingService()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 
SetUpCommandLine(CommandLine * command_line)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 
SetTestStep(int step)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:
SafeBrowsingServiceTestHelper(SafeBrowsingServiceTest * safe_browsing_test)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.
OnBrowseUrlCheckResult(const GURL & url,SafeBrowsingService::UrlCheckResult result)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   }
OnDownloadUrlCheckResult(const std::vector<GURL> & url_chain,SafeBrowsingService::UrlCheckResult result)363   virtual void OnDownloadUrlCheckResult(
364       const std::vector<GURL>& url_chain,
365       SafeBrowsingService::UrlCheckResult result) {
366     // TODO(lzheng): Add test for DownloadUrl.
367   }
368 
OnBlockingPageComplete(bool proceed)369   virtual void OnBlockingPageComplete(bool proceed) {
370     NOTREACHED() << "Not implemented.";
371   }
372 
373   // Functions and callbacks to start the safebrowsing database update.
ForceUpdate()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   }
ForceUpdateInIOThread()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   }
OnForceUpdateDone()388   void OnForceUpdateDone() {
389     StopUILoop();
390   }
391 
392   // Functions and callbacks related to CheckUrl. These are used to verify
393   // phishing URLs.
CheckUrl(const GURL & url)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   }
CheckUrlOnIOThread(const GURL & url)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 
OnCheckUrlDone()411   void OnCheckUrlDone() {
412     StopUILoop();
413   }
414 
415   // Updates status from IO Thread.
CheckStatusOnIOThread()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.
CheckIsDatabaseReady()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 
OnWaitForStatusUpdateDone()433   void OnWaitForStatusUpdateDone() {
434     StopUILoop();
435   }
436 
437   // Wait for a given period to get safebrowsing status updated.
WaitForStatusUpdate(int64 wait_time_msec)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 
WaitTillServerReady(const char * host,int port)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.
FetchDBToVerify(const char * host,int port,int test_step)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.
FetchUrlsToVerify(const char * host,int port,int test_step)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.
VerifyTestComplete(const char * host,int port,int test_step)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.
OnURLFetchComplete(const URLFetcher * source,const GURL & url,const net::URLRequestStatus & status,int response_code,const ResponseCookies & cookies,const std::string & data)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 
response_data()507   const std::string& response_data() {
508     return response_data_;
509   }
510 
511  private:
512   // Stops UI loop after desired status is updated.
StopUILoop()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.
FetchUrl(const GURL & url)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 
IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest,SafeBrowsingSystemTest)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