safe_browsing_test.cc revision 513209b27ff55e2841eac0e4120199c23acce758
1// Copyright (c) 2010 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/condition_variable.h"
21#include "base/environment.h"
22#include "base/lock.h"
23#include "base/path_service.h"
24#include "base/process_util.h"
25#include "base/string_number_conversions.h"
26#include "base/string_util.h"
27#include "base/string_split.h"
28#include "base/time.h"
29#include "base/utf_string_conversions.h"
30#include "chrome/browser/browser_process.h"
31#include "chrome/browser/browser_thread.h"
32#include "chrome/browser/profile.h"
33#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
34#include "chrome/browser/safe_browsing/protocol_manager.h"
35#include "chrome/browser/safe_browsing/safe_browsing_service.h"
36#include "chrome/common/chrome_switches.h"
37#include "chrome/common/url_constants.h"
38#include "chrome/test/in_process_browser_test.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
47namespace {
48
49const FilePath::CharType kDataFile[] = FILE_PATH_LITERAL("testing_input.dat");
50const char kUrlVerifyPath[] = "/safebrowsing/verify_urls";
51const char kDBVerifyPath[] = "/safebrowsing/verify_database";
52const char kDBResetPath[] = "/reset";
53const char kTestCompletePath[] = "/test_complete";
54
55struct 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// ...
66bool 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
103class 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 (!PathService::Get(base::DIR_EXE, &pyproto_code_dir)) {
132      LOG(ERROR) << "Failed to get DIR_EXE";
133      return false;
134    }
135    pyproto_code_dir = pyproto_code_dir.Append(FILE_PATH_LITERAL("pyproto"));
136    AppendToPythonPath(pyproto_code_dir);
137    pyproto_code_dir = pyproto_code_dir.Append(FILE_PATH_LITERAL("google"));
138    AppendToPythonPath(pyproto_code_dir);
139
140    FilePath python_runtime;
141    EXPECT_TRUE(GetPythonRunTime(&python_runtime));
142    CommandLine cmd_line(python_runtime);
143    FilePath datafile = testserver_path.Append(datafile_);
144    cmd_line.AppendArgPath(testserver);
145    cmd_line.AppendSwitchASCII("port", StringPrintf("%d", kPort_));
146    cmd_line.AppendSwitchPath("datafile", datafile);
147
148    if (!base::LaunchApp(cmd_line, false, true, &server_handle_)) {
149      LOG(ERROR) << "Failed to launch server: "
150                 << cmd_line.command_line_string();
151      return false;
152    }
153    return true;
154  }
155
156  // Stop the python server test suite.
157  bool Stop() {
158    if (server_handle_ == base::kNullProcessHandle)
159      return true;
160
161    // First check if the process has already terminated.
162    if (!base::WaitForSingleProcess(server_handle_, 0) &&
163        !base::KillProcess(server_handle_, 1, true)) {
164      VLOG(1) << "Kill failed?";
165      return false;
166    }
167
168    base::CloseProcessHandle(server_handle_);
169    server_handle_ = base::kNullProcessHandle;
170    VLOG(1) << "Stopped.";
171    return true;
172  }
173
174  static const char* Host() {
175    return kHost_;
176  }
177
178  static int Port() {
179    return kPort_;
180  }
181
182 private:
183  static const char kHost_[];
184  static const int kPort_;
185  FilePath datafile_;
186  base::ProcessHandle server_handle_;
187  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingTestServer);
188};
189
190const char SafeBrowsingTestServer::kHost_[] = "localhost";
191const int SafeBrowsingTestServer::kPort_ = 40102;
192
193// This starts the browser and keeps status of states related to SafeBrowsing.
194class SafeBrowsingServiceTest : public InProcessBrowserTest {
195 public:
196  SafeBrowsingServiceTest()
197    : safe_browsing_service_(NULL),
198      is_database_ready_(true),
199      is_initial_request_(false),
200      is_update_scheduled_(false),
201      is_checked_url_in_db_(false),
202      is_checked_url_safe_(false) {
203  }
204
205  virtual ~SafeBrowsingServiceTest() {
206  }
207
208  void UpdateSafeBrowsingStatus() {
209    ASSERT_TRUE(safe_browsing_service_);
210    AutoLock lock(update_status_mutex_);
211    is_initial_request_ =
212        safe_browsing_service_->protocol_manager_->is_initial_request();
213    last_update_ = safe_browsing_service_->protocol_manager_->last_update();
214    is_update_scheduled_ =
215        safe_browsing_service_->protocol_manager_->update_timer_.IsRunning();
216  }
217
218  void ForceUpdate() {
219    ASSERT_TRUE(safe_browsing_service_);
220    safe_browsing_service_->protocol_manager_->ForceScheduleNextUpdate(0);
221  }
222
223  void CheckIsDatabaseReady() {
224    AutoLock lock(update_status_mutex_);
225    is_database_ready_ =
226        !safe_browsing_service_->database_update_in_progress_;
227  }
228
229  void CheckUrl(SafeBrowsingService::Client* helper, const GURL& url) {
230    ASSERT_TRUE(safe_browsing_service_);
231    AutoLock lock(update_status_mutex_);
232    if (safe_browsing_service_->CheckUrl(url, helper)) {
233      is_checked_url_in_db_ = false;
234      is_checked_url_safe_ = true;
235    } else {
236      // In this case, Safebrowsing service will fetch the full hash
237      // from the server and examine that. Once it is done,
238      // set_is_checked_url_safe() will be called via callback.
239      is_checked_url_in_db_ = true;
240    }
241  }
242
243  bool is_checked_url_in_db() {
244    AutoLock l(update_status_mutex_);
245    return is_checked_url_in_db_;
246  }
247
248  void set_is_checked_url_safe(bool safe) {
249    AutoLock l(update_status_mutex_);
250    is_checked_url_safe_ = safe;
251  }
252
253  bool is_checked_url_safe() {
254    AutoLock l(update_status_mutex_);
255    return is_checked_url_safe_;
256  }
257
258  bool is_database_ready() {
259    AutoLock l(update_status_mutex_);
260    return is_database_ready_;
261  }
262
263  bool is_initial_request() {
264    AutoLock l(update_status_mutex_);
265    return is_initial_request_;
266  }
267
268  base::Time last_update() {
269    AutoLock l(update_status_mutex_);
270    return last_update_;
271  }
272
273  bool is_update_scheduled() {
274    AutoLock l(update_status_mutex_);
275    return is_update_scheduled_;
276  }
277
278  MessageLoop* SafeBrowsingMessageLoop() {
279    return safe_browsing_service_->safe_browsing_thread_->message_loop();
280  }
281
282 protected:
283  bool InitSafeBrowsingService() {
284    safe_browsing_service_ =
285        g_browser_process->resource_dispatcher_host()->safe_browsing_service();
286    return safe_browsing_service_ != NULL;
287  }
288
289  virtual void SetUpCommandLine(CommandLine* command_line) {
290    // Makes sure the auto update is not triggered. This test will force the
291    // update when needed.
292    command_line->AppendSwitch(switches::kSbDisableAutoUpdate);
293
294    // In this test, we fetch SafeBrowsing data and Mac key from the same
295    // server. Although in real production, they are served from different
296    // servers.
297    std::string url_prefix =
298        StringPrintf("http://%s:%d/safebrowsing",
299                     SafeBrowsingTestServer::Host(),
300                     SafeBrowsingTestServer::Port());
301    command_line->AppendSwitchASCII(switches::kSbInfoURLPrefix, url_prefix);
302    command_line->AppendSwitchASCII(switches::kSbMacKeyURLPrefix, url_prefix);
303  }
304
305  void SetTestStep(int step) {
306    std::string test_step = StringPrintf("test_step=%d", step);
307    safe_browsing_service_->protocol_manager_->set_additional_query(test_step);
308  }
309
310 private:
311  SafeBrowsingService* safe_browsing_service_;
312
313  // Protects all variables below since they are read on UI thread
314  // but updated on IO thread or safebrowsing thread.
315  Lock update_status_mutex_;
316
317  // States associated with safebrowsing service updates.
318  bool is_database_ready_;
319  bool is_initial_request_;
320  base::Time last_update_;
321  bool is_update_scheduled_;
322  // Indicates if there is a match between a URL's prefix and safebrowsing
323  // database (thus potentially it is a phishing URL).
324  bool is_checked_url_in_db_;
325  // True if last verified URL is not a phishing URL and thus it is safe.
326  bool is_checked_url_safe_;
327
328  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTest);
329};
330
331// A ref counted helper class that handles callbacks between IO thread and UI
332// thread.
333class SafeBrowsingServiceTestHelper
334    : public base::RefCountedThreadSafe<SafeBrowsingServiceTestHelper>,
335      public SafeBrowsingService::Client,
336      public URLFetcher::Delegate {
337 public:
338  explicit SafeBrowsingServiceTestHelper(
339      SafeBrowsingServiceTest* safe_browsing_test)
340      : safe_browsing_test_(safe_browsing_test),
341        response_status_(URLRequestStatus::FAILED) {
342  }
343
344  // Callbacks for SafeBrowsingService::Client.
345  virtual void OnUrlCheckResult(const GURL& url,
346                                SafeBrowsingService::UrlCheckResult result) {
347    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
348    EXPECT_TRUE(safe_browsing_test_->is_checked_url_in_db());
349    safe_browsing_test_->set_is_checked_url_safe(
350        result == SafeBrowsingService::URL_SAFE);
351    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
352                            NewRunnableMethod(this,
353                            &SafeBrowsingServiceTestHelper::OnCheckUrlDone));
354  }
355  virtual void OnBlockingPageComplete(bool proceed) {
356    NOTREACHED() << "Not implemented.";
357  }
358
359  // Functions and callbacks to start the safebrowsing database update.
360  void ForceUpdate() {
361    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
362        NewRunnableMethod(this,
363        &SafeBrowsingServiceTestHelper::ForceUpdateInIOThread));
364    // Will continue after OnForceUpdateDone().
365    ui_test_utils::RunMessageLoop();
366  }
367  void ForceUpdateInIOThread() {
368    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
369    safe_browsing_test_->ForceUpdate();
370    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
371        NewRunnableMethod(this,
372        &SafeBrowsingServiceTestHelper::OnForceUpdateDone));
373  }
374  void OnForceUpdateDone() {
375    StopUILoop();
376  }
377
378  // Functions and callbacks related to CheckUrl. These are used to verify
379  // phishing URLs.
380  void CheckUrl(const GURL& url) {
381    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, NewRunnableMethod(
382        this, &SafeBrowsingServiceTestHelper::CheckUrlOnIOThread, url));
383    ui_test_utils::RunMessageLoop();
384  }
385  void CheckUrlOnIOThread(const GURL& url) {
386    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
387    safe_browsing_test_->CheckUrl(this, url);
388    if (!safe_browsing_test_->is_checked_url_in_db()) {
389      // Ends the checking since this URL's prefix is not in database.
390      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
391          this, &SafeBrowsingServiceTestHelper::OnCheckUrlDone));
392    }
393    // Otherwise, OnCheckUrlDone is called in OnUrlCheckResult since
394    // safebrowsing service further fetches hashes from safebrowsing server.
395  }
396
397  void OnCheckUrlDone() {
398    StopUILoop();
399  }
400
401  // Updates status from IO Thread.
402  void CheckStatusOnIOThread() {
403    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
404    safe_browsing_test_->UpdateSafeBrowsingStatus();
405    safe_browsing_test_->SafeBrowsingMessageLoop()->PostTask(
406        FROM_HERE, NewRunnableMethod(this,
407        &SafeBrowsingServiceTestHelper::CheckIsDatabaseReady));
408  }
409
410  // Checks status in SafeBrowsing Thread.
411  void CheckIsDatabaseReady() {
412    EXPECT_EQ(MessageLoop::current(),
413              safe_browsing_test_->SafeBrowsingMessageLoop());
414    safe_browsing_test_->CheckIsDatabaseReady();
415    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
416        this, &SafeBrowsingServiceTestHelper::OnWaitForStatusUpdateDone));
417  }
418
419  void OnWaitForStatusUpdateDone() {
420    StopUILoop();
421  }
422
423  // Wait for a given period to get safebrowsing status updated.
424  void WaitForStatusUpdate(int64 wait_time_msec) {
425    BrowserThread::PostDelayedTask(
426        BrowserThread::IO,
427        FROM_HERE,
428        NewRunnableMethod(this,
429            &SafeBrowsingServiceTestHelper::CheckStatusOnIOThread),
430        wait_time_msec);
431    // Will continue after OnWaitForStatusUpdateDone().
432    ui_test_utils::RunMessageLoop();
433  }
434
435  void WaitTillServerReady(const char* host, int port) {
436    response_status_ = URLRequestStatus::FAILED;
437    GURL url(StringPrintf("http://%s:%d%s?test_step=0",
438                          host, port, kDBResetPath));
439    // TODO(lzheng): We should have a way to reliably tell when a server is
440    // ready so we could get rid of the Sleep and retry loop.
441    while (true) {
442      if (FetchUrl(url) == URLRequestStatus::SUCCESS)
443        break;
444      // Wait and try again if last fetch was failed. The loop will hit the
445      // timeout in OutOfProcTestRunner if the fetch can not get success
446      // response.
447      PlatformThread::Sleep(TestTimeouts::action_timeout_ms());
448    }
449  }
450
451  // Calls test server to fetch database for verification.
452  URLRequestStatus::Status FetchDBToVerify(const char* host, int port,
453                                           int test_step) {
454    // TODO(lzheng): Remove chunk_type=add once it is not needed by the server.
455    GURL url(StringPrintf("http://%s:%d%s?"
456                          "client=chromium&appver=1.0&pver=2.2&test_step=%d&"
457                          "chunk_type=add",
458                          host, port, kDBVerifyPath, test_step));
459    return FetchUrl(url);
460  }
461
462  // Calls test server to fetch URLs for verification.
463  URLRequestStatus::Status FetchUrlsToVerify(const char* host, int port,
464                                             int test_step) {
465    GURL url(StringPrintf("http://%s:%d%s?"
466                          "client=chromium&appver=1.0&pver=2.2&test_step=%d",
467                          host, port, kUrlVerifyPath, test_step));
468    return FetchUrl(url);
469  }
470
471  // Calls test server to check if test data is done. E.g.: if there is a
472  // bad URL that server expects test to fetch full hash but the test didn't,
473  // this verification will fail.
474  URLRequestStatus::Status VerifyTestComplete(const char* host, int port,
475                                              int test_step) {
476    GURL url(StringPrintf("http://%s:%d%s?test_step=%d",
477                          host, port, kTestCompletePath, test_step));
478    return FetchUrl(url);
479  }
480
481  // Callback for URLFetcher.
482  virtual void OnURLFetchComplete(const URLFetcher* source,
483                                  const GURL& url,
484                                  const URLRequestStatus& status,
485                                  int response_code,
486                                  const ResponseCookies& cookies,
487                                  const std::string& data) {
488    response_data_ = data;
489    response_status_ = status.status();
490    StopUILoop();
491  }
492
493  const std::string& response_data() {
494    return response_data_;
495  }
496
497 private:
498  // Stops UI loop after desired status is updated.
499  void StopUILoop() {
500    EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
501    MessageLoopForUI::current()->Quit();
502  }
503
504  // Fetch a URL. If message_loop_started is true, starts the message loop
505  // so the caller could wait till OnURLFetchComplete is called.
506  URLRequestStatus::Status FetchUrl(const GURL& url) {
507    url_fetcher_.reset(new URLFetcher(url, URLFetcher::GET, this));
508    url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE);
509    url_fetcher_->set_request_context(Profile::GetDefaultRequestContext());
510    url_fetcher_->Start();
511    ui_test_utils::RunMessageLoop();
512    return response_status_;
513  }
514
515  base::OneShotTimer<SafeBrowsingServiceTestHelper> check_update_timer_;
516  SafeBrowsingServiceTest* safe_browsing_test_;
517  scoped_ptr<URLFetcher> url_fetcher_;
518  std::string response_data_;
519  URLRequestStatus::Status response_status_;
520  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTestHelper);
521};
522
523
524#if defined(OS_MACOSX)
525// TODO(lzheng): http://crbug.com/62415, can not start on MacOS.
526#define SafeBrowsingSystemTest DISABLED_SafeBrowsingSystemTest
527#endif
528IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, SafeBrowsingSystemTest) {
529  LOG(INFO) << "Start test";
530  const char* server_host = SafeBrowsingTestServer::Host();
531  int server_port = SafeBrowsingTestServer::Port();
532  ASSERT_TRUE(InitSafeBrowsingService());
533
534  scoped_refptr<SafeBrowsingServiceTestHelper> safe_browsing_helper(
535      new SafeBrowsingServiceTestHelper(this));
536  int last_step = 0;
537  FilePath datafile_path = FilePath(kDataFile);
538  SafeBrowsingTestServer test_server(datafile_path);
539  ASSERT_TRUE(test_server.Start());
540
541  // Make sure the server is running.
542  safe_browsing_helper->WaitTillServerReady(server_host, server_port);
543
544  // Waits and makes sure safebrowsing update is not happening.
545  // The wait will stop once OnWaitForStatusUpdateDone in
546  // safe_browsing_helper is called and status from safe_browsing_service_
547  // is checked.
548  safe_browsing_helper->WaitForStatusUpdate(0);
549  EXPECT_TRUE(is_database_ready());
550  EXPECT_TRUE(is_initial_request());
551  EXPECT_FALSE(is_update_scheduled());
552  EXPECT_TRUE(last_update().is_null());
553  // Starts updates. After each update, the test will fetch a list of URLs with
554  // expected results to verify with safebrowsing service. If there is no error,
555  // the test moves on to the next step to get more update chunks.
556  // This repeats till there is no update data.
557  for (int step = 1;; step++) {
558    // Every step should be a fresh start.
559    SCOPED_TRACE(StringPrintf("step=%d", step));
560    EXPECT_TRUE(is_database_ready());
561    EXPECT_FALSE(is_update_scheduled());
562
563    // TODO(lzheng): Remove the following #if and #elif to enable the rest of
564    // the test once bot is restarted with change
565    // http://codereview.chromium.org/3750002.
566#if defined(OS_WIN)
567    break;
568#elif defined(OS_POSIX)
569    if (step > 2 ) break;
570#endif
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(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(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  // TODO(lzheng): Enable this check after safebrowsing server updated with
633  // the latest data in the next revision.
634
635  // Verifies with server if test is done and waits till server responses.
636  // EXPECT_EQ(URLRequestStatus::SUCCESS,
637  //           safe_browsing_helper->VerifyTestComplete(server_host,
638  //                                                    server_port,
639  //                                                    last_step));
640  // EXPECT_EQ("yes", safe_browsing_helper->response_data());
641  test_server.Stop();
642}
643