- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / safe_browsing / protocol_manager_unittest.cc
1 // Copyright (c) 2012 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
6 #include "base/strings/stringprintf.h"
7 #include "base/test/test_simple_task_runner.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "base/time/time.h"
10 #include "chrome/browser/safe_browsing/protocol_manager.h"
11 #include "google_apis/google_api_keys.h"
12 #include "net/base/escape.h"
13 #include "net/base/load_flags.h"
14 #include "net/base/net_errors.h"
15 #include "net/url_request/test_url_fetcher_factory.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gmock_mutant.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using base::Time;
21 using base::TimeDelta;
22 using testing::_;
23 using testing::Invoke;
24
25 static const char kUrlPrefix[] = "https://prefix.com/foo";
26 static const char kBackupConnectUrlPrefix[] = "https://alt1-prefix.com/foo";
27 static const char kBackupHttpUrlPrefix[] = "https://alt2-prefix.com/foo";
28 static const char kBackupNetworkUrlPrefix[] = "https://alt3-prefix.com/foo";
29 static const char kClient[] = "unittest";
30 static const char kAppVer[] = "1.0";
31 static const char kAdditionalQuery[] = "additional_query";
32
33 class SafeBrowsingProtocolManagerTest : public testing::Test {
34  protected:
35   std::string key_param_;
36
37   virtual void SetUp() {
38     std::string key = google_apis::GetAPIKey();
39     if (!key.empty()) {
40       key_param_ = base::StringPrintf(
41           "&key=%s",
42           net::EscapeQueryParamValue(key, true).c_str());
43     }
44   }
45
46   scoped_ptr<SafeBrowsingProtocolManager> CreateProtocolManager(
47       SafeBrowsingProtocolManagerDelegate* delegate) {
48     SafeBrowsingProtocolConfig config;
49     config.client_name = kClient;
50     config.url_prefix = kUrlPrefix;
51     config.backup_connect_error_url_prefix = kBackupConnectUrlPrefix;
52     config.backup_http_error_url_prefix = kBackupHttpUrlPrefix;
53     config.backup_network_error_url_prefix = kBackupNetworkUrlPrefix;
54     config.version = kAppVer;
55
56     return scoped_ptr<SafeBrowsingProtocolManager>(
57         SafeBrowsingProtocolManager::Create(delegate, NULL, config));
58   }
59
60   void ValidateUpdateFetcherRequest(
61       const net::TestURLFetcher* url_fetcher,
62       const std::string& expected_prefix) {
63     ASSERT_TRUE(url_fetcher);
64     EXPECT_EQ(net::LOAD_DISABLE_CACHE, url_fetcher->GetLoadFlags());
65     EXPECT_EQ("goog-phish-shavar;\ngoog-malware-shavar;\n",
66               url_fetcher->upload_data());
67     EXPECT_EQ(GURL(expected_prefix + "/downloads?client=unittest&appver=1.0"
68                    "&pver=2.2" + key_param_),
69               url_fetcher->GetOriginalURL());
70   }
71
72   void ValidateUpdateFetcherRequest(const net::TestURLFetcher* url_fetcher) {
73     ValidateUpdateFetcherRequest(url_fetcher, kUrlPrefix);
74   }
75
76   void ValidateRedirectFetcherRequest(const net::TestURLFetcher* url_fetcher,
77                                       const std::string& expected_url) {
78     ASSERT_TRUE(url_fetcher);
79     EXPECT_EQ(net::LOAD_DISABLE_CACHE, url_fetcher->GetLoadFlags());
80     EXPECT_EQ("", url_fetcher->upload_data());
81     EXPECT_EQ(GURL(expected_url), url_fetcher->GetOriginalURL());
82   }
83 };
84
85 // Ensure that we respect section 5 of the SafeBrowsing protocol specification.
86 TEST_F(SafeBrowsingProtocolManagerTest, TestBackOffTimes) {
87   scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
88
89   pm->next_update_interval_ = TimeDelta::FromSeconds(1800);
90   ASSERT_TRUE(pm->back_off_fuzz_ >= 0.0 && pm->back_off_fuzz_ <= 1.0);
91
92   TimeDelta next;
93
94   // No errors received so far.
95   next = pm->GetNextUpdateInterval(false);
96   EXPECT_EQ(next, TimeDelta::FromSeconds(1800));
97
98   // 1 error.
99   next = pm->GetNextUpdateInterval(true);
100   EXPECT_EQ(next, TimeDelta::FromSeconds(60));
101
102   // 2 errors.
103   next = pm->GetNextUpdateInterval(true);
104   EXPECT_TRUE(next >= TimeDelta::FromMinutes(30) &&
105               next <= TimeDelta::FromMinutes(60));
106
107   // 3 errors.
108   next = pm->GetNextUpdateInterval(true);
109   EXPECT_TRUE(next >= TimeDelta::FromMinutes(60) &&
110               next <= TimeDelta::FromMinutes(120));
111
112   // 4 errors.
113   next = pm->GetNextUpdateInterval(true);
114   EXPECT_TRUE(next >= TimeDelta::FromMinutes(120) &&
115               next <= TimeDelta::FromMinutes(240));
116
117   // 5 errors.
118   next = pm->GetNextUpdateInterval(true);
119   EXPECT_TRUE(next >= TimeDelta::FromMinutes(240) &&
120               next <= TimeDelta::FromMinutes(480));
121
122   // 6 errors, reached max backoff.
123   next = pm->GetNextUpdateInterval(true);
124   EXPECT_EQ(next, TimeDelta::FromMinutes(480));
125
126   // 7 errors.
127   next = pm->GetNextUpdateInterval(true);
128   EXPECT_EQ(next, TimeDelta::FromMinutes(480));
129
130   // Received a successful response.
131   next = pm->GetNextUpdateInterval(false);
132   EXPECT_EQ(next, TimeDelta::FromSeconds(1800));
133 }
134
135 TEST_F(SafeBrowsingProtocolManagerTest, TestChunkStrings) {
136   scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
137
138   // Add and Sub chunks.
139   SBListChunkRanges phish("goog-phish-shavar");
140   phish.adds = "1,4,6,8-20,99";
141   phish.subs = "16,32,64-96";
142   EXPECT_EQ(pm->FormatList(phish),
143             "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96\n");
144
145   // Add chunks only.
146   phish.subs = "";
147   EXPECT_EQ(pm->FormatList(phish), "goog-phish-shavar;a:1,4,6,8-20,99\n");
148
149   // Sub chunks only.
150   phish.adds = "";
151   phish.subs = "16,32,64-96";
152   EXPECT_EQ(pm->FormatList(phish), "goog-phish-shavar;s:16,32,64-96\n");
153
154   // No chunks of either type.
155   phish.adds = "";
156   phish.subs = "";
157   EXPECT_EQ(pm->FormatList(phish), "goog-phish-shavar;\n");
158 }
159
160 TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashBackOffTimes) {
161   scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
162
163   // No errors or back off time yet.
164   EXPECT_EQ(pm->gethash_error_count_, 0);
165   EXPECT_TRUE(pm->next_gethash_time_.is_null());
166
167   Time now = Time::Now();
168
169   // 1 error.
170   pm->HandleGetHashError(now);
171   EXPECT_EQ(pm->gethash_error_count_, 1);
172   TimeDelta margin = TimeDelta::FromSeconds(5);  // Fudge factor.
173   Time future = now + TimeDelta::FromMinutes(1);
174   EXPECT_TRUE(pm->next_gethash_time_ >= future - margin &&
175               pm->next_gethash_time_ <= future + margin);
176
177   // 2 errors.
178   pm->HandleGetHashError(now);
179   EXPECT_EQ(pm->gethash_error_count_, 2);
180   EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(30));
181   EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(60));
182
183   // 3 errors.
184   pm->HandleGetHashError(now);
185   EXPECT_EQ(pm->gethash_error_count_, 3);
186   EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(60));
187   EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(120));
188
189   // 4 errors.
190   pm->HandleGetHashError(now);
191   EXPECT_EQ(pm->gethash_error_count_, 4);
192   EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(120));
193   EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(240));
194
195   // 5 errors.
196   pm->HandleGetHashError(now);
197   EXPECT_EQ(pm->gethash_error_count_, 5);
198   EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(240));
199   EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(480));
200
201   // 6 errors, reached max backoff.
202   pm->HandleGetHashError(now);
203   EXPECT_EQ(pm->gethash_error_count_, 6);
204   EXPECT_TRUE(pm->next_gethash_time_ == now + TimeDelta::FromMinutes(480));
205
206   // 7 errors.
207   pm->HandleGetHashError(now);
208   EXPECT_EQ(pm->gethash_error_count_, 7);
209   EXPECT_TRUE(pm->next_gethash_time_== now + TimeDelta::FromMinutes(480));
210 }
211
212 TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashUrl) {
213   scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
214
215   EXPECT_EQ("https://prefix.com/foo/gethash?client=unittest&appver=1.0&"
216             "pver=2.2" + key_param_, pm->GetHashUrl().spec());
217
218   pm->set_additional_query(kAdditionalQuery);
219   EXPECT_EQ("https://prefix.com/foo/gethash?client=unittest&appver=1.0&"
220             "pver=2.2" + key_param_ + "&additional_query",
221             pm->GetHashUrl().spec());
222 }
223
224 TEST_F(SafeBrowsingProtocolManagerTest, TestUpdateUrl) {
225   scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
226
227   EXPECT_EQ("https://prefix.com/foo/downloads?client=unittest&appver=1.0&"
228             "pver=2.2" + key_param_, pm->UpdateUrl().spec());
229
230   pm->set_additional_query(kAdditionalQuery);
231   EXPECT_EQ("https://prefix.com/foo/downloads?client=unittest&appver=1.0&"
232             "pver=2.2" + key_param_ + "&additional_query",
233             pm->UpdateUrl().spec());
234 }
235
236 TEST_F(SafeBrowsingProtocolManagerTest, TestNextChunkUrl) {
237   scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
238
239   std::string url_partial = "localhost:1234/foo/bar?foo";
240   std::string url_http_full = "http://localhost:1234/foo/bar?foo";
241   std::string url_https_full = "https://localhost:1234/foo/bar?foo";
242   std::string url_https_no_query = "https://localhost:1234/foo/bar";
243
244   EXPECT_EQ("https://localhost:1234/foo/bar?foo",
245             pm->NextChunkUrl(url_partial).spec());
246   EXPECT_EQ("http://localhost:1234/foo/bar?foo",
247             pm->NextChunkUrl(url_http_full).spec());
248   EXPECT_EQ("https://localhost:1234/foo/bar?foo",
249             pm->NextChunkUrl(url_https_full).spec());
250   EXPECT_EQ("https://localhost:1234/foo/bar",
251             pm->NextChunkUrl(url_https_no_query).spec());
252
253   pm->set_additional_query(kAdditionalQuery);
254   EXPECT_EQ("https://localhost:1234/foo/bar?foo&additional_query",
255             pm->NextChunkUrl(url_partial).spec());
256   EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
257             pm->NextChunkUrl(url_http_full).spec());
258   EXPECT_EQ("https://localhost:1234/foo/bar?foo&additional_query",
259             pm->NextChunkUrl(url_https_full).spec());
260   EXPECT_EQ("https://localhost:1234/foo/bar?additional_query",
261             pm->NextChunkUrl(url_https_no_query).spec());
262 }
263
264 namespace {
265
266 class MockProtocolDelegate : public SafeBrowsingProtocolManagerDelegate {
267  public:
268   MockProtocolDelegate() {}
269   virtual ~MockProtocolDelegate() {}
270
271   MOCK_METHOD0(UpdateStarted, void());
272   MOCK_METHOD1(UpdateFinished, void(bool));
273   MOCK_METHOD0(ResetDatabase, void());
274   MOCK_METHOD1(GetChunks, void(GetChunksCallback));
275   MOCK_METHOD3(AddChunks, void(const std::string&, SBChunkList*,
276                                AddChunksCallback));
277   MOCK_METHOD1(DeleteChunks, void(std::vector<SBChunkDelete>*));
278 };
279
280 // |InvokeGetChunksCallback| is required because GMock's InvokeArgument action
281 // expects to use operator(), and a Callback only provides Run().
282 // TODO(cbentzel): Use ACTION or ACTION_TEMPLATE instead?
283 void InvokeGetChunksCallback(
284     const std::vector<SBListChunkRanges>& ranges,
285     bool database_error,
286     SafeBrowsingProtocolManagerDelegate::GetChunksCallback callback) {
287   callback.Run(ranges, database_error);
288 }
289
290 // |HandleAddChunks| deletes the chunks and asynchronously invokes
291 // |callback| since SafeBrowsingProtocolManager is not re-entrant at the time
292 // this is called. This guarantee is part of the
293 // SafeBrowsingProtocolManagerDelegate contract.
294 void HandleAddChunks(
295     const std::string& unused_list,
296     SBChunkList* chunks,
297     SafeBrowsingProtocolManagerDelegate::AddChunksCallback callback) {
298   delete chunks;
299   scoped_refptr<base::SingleThreadTaskRunner> task_runner(
300       base::ThreadTaskRunnerHandle::Get());
301   if (!task_runner.get())
302     return;
303   task_runner->PostTask(FROM_HERE, callback);
304 }
305
306 }  // namespace
307
308 // Tests that the Update protocol will be skipped if there are problems
309 // accessing the database.
310 TEST_F(SafeBrowsingProtocolManagerTest, ProblemAccessingDatabase) {
311   scoped_refptr<base::TestSimpleTaskRunner> runner(
312       new base::TestSimpleTaskRunner());
313   base::ThreadTaskRunnerHandle runner_handler(runner);
314
315   testing::StrictMock<MockProtocolDelegate> test_delegate;
316   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
317   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
318       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
319                                     std::vector<SBListChunkRanges>(),
320                                     true)));
321   EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
322
323   scoped_ptr<SafeBrowsingProtocolManager> pm(
324       CreateProtocolManager(&test_delegate));
325
326   pm->ForceScheduleNextUpdate(TimeDelta());
327   runner->RunPendingTasks();
328
329   EXPECT_TRUE(pm->IsUpdateScheduled());
330 }
331
332 // Tests the contents of the POST body when there are contents in the
333 // local database. This is not exhaustive, as the actual list formatting
334 // is covered by SafeBrowsingProtocolManagerTest.TestChunkStrings.
335 TEST_F(SafeBrowsingProtocolManagerTest, ExistingDatabase) {
336   scoped_refptr<base::TestSimpleTaskRunner> runner(
337       new base::TestSimpleTaskRunner());
338   base::ThreadTaskRunnerHandle runner_handler(runner);
339   net::TestURLFetcherFactory url_fetcher_factory;
340
341   std::vector<SBListChunkRanges> ranges;
342   SBListChunkRanges range_phish(safe_browsing_util::kPhishingList);
343   range_phish.adds = "adds_phish";
344   range_phish.subs = "subs_phish";
345   ranges.push_back(range_phish);
346
347   SBListChunkRanges range_unknown("unknown_list");
348   range_unknown.adds = "adds_unknown";
349   range_unknown.subs = "subs_unknown";
350   ranges.push_back(range_unknown);
351
352   testing::StrictMock<MockProtocolDelegate> test_delegate;
353   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
354   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
355       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
356                                     ranges,
357                                     false)));
358   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
359
360   scoped_ptr<SafeBrowsingProtocolManager> pm(
361       CreateProtocolManager(&test_delegate));
362
363   // Kick off initialization. This returns chunks from the DB synchronously.
364   pm->ForceScheduleNextUpdate(TimeDelta());
365   runner->RunPendingTasks();
366
367   // We should have an URLFetcher at this point in time.
368   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
369   ASSERT_TRUE(url_fetcher);
370   EXPECT_EQ(net::LOAD_DISABLE_CACHE, url_fetcher->GetLoadFlags());
371   EXPECT_EQ("goog-phish-shavar;a:adds_phish:s:subs_phish\n"
372             "unknown_list;a:adds_unknown:s:subs_unknown\n"
373             "goog-malware-shavar;\n",
374             url_fetcher->upload_data());
375   EXPECT_EQ(GURL("https://prefix.com/foo/downloads?client=unittest&appver=1.0"
376                  "&pver=2.2" + key_param_),
377             url_fetcher->GetOriginalURL());
378
379   url_fetcher->set_status(net::URLRequestStatus());
380   url_fetcher->set_response_code(200);
381   url_fetcher->SetResponseString(std::string());
382   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
383
384   EXPECT_TRUE(pm->IsUpdateScheduled());
385 }
386
387 TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseBadBodyBackupSuccess) {
388   scoped_refptr<base::TestSimpleTaskRunner> runner(
389       new base::TestSimpleTaskRunner());
390   base::ThreadTaskRunnerHandle runner_handler(runner);
391   net::TestURLFetcherFactory url_fetcher_factory;
392
393   testing::StrictMock<MockProtocolDelegate> test_delegate;
394   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
395   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
396       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
397                                     std::vector<SBListChunkRanges>(),
398                                     false)));
399   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
400
401   scoped_ptr<SafeBrowsingProtocolManager> pm(
402       CreateProtocolManager(&test_delegate));
403
404   // Kick off initialization. This returns chunks from the DB synchronously.
405   pm->ForceScheduleNextUpdate(TimeDelta());
406   runner->RunPendingTasks();
407
408   // We should have an URLFetcher at this point in time.
409   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
410   ValidateUpdateFetcherRequest(url_fetcher);
411
412   // The update response is successful, but an invalid body.
413   url_fetcher->set_status(net::URLRequestStatus());
414   url_fetcher->set_response_code(200);
415   url_fetcher->SetResponseString("THIS_IS_A_BAD_RESPONSE");
416   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
417
418   // There should now be a backup request.
419   net::TestURLFetcher* backup_url_fetcher =
420       url_fetcher_factory.GetFetcherByID(1);
421   ValidateUpdateFetcherRequest(backup_url_fetcher,
422                                kBackupHttpUrlPrefix);
423
424   // Respond to the backup successfully.
425   backup_url_fetcher->set_status(net::URLRequestStatus());
426   backup_url_fetcher->set_response_code(200);
427   backup_url_fetcher->SetResponseString(std::string());
428   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
429
430   EXPECT_TRUE(pm->IsUpdateScheduled());
431 }
432
433 // Tests what happens when there is an HTTP error response to the update
434 // request, as well as an error response to the backup update request.
435 TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseHttpErrorBackupError) {
436   scoped_refptr<base::TestSimpleTaskRunner> runner(
437       new base::TestSimpleTaskRunner());
438   base::ThreadTaskRunnerHandle runner_handler(runner);
439   net::TestURLFetcherFactory url_fetcher_factory;
440
441   testing::StrictMock<MockProtocolDelegate> test_delegate;
442   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
443   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
444       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
445                                     std::vector<SBListChunkRanges>(),
446                                     false)));
447   EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
448
449   scoped_ptr<SafeBrowsingProtocolManager> pm(
450       CreateProtocolManager(&test_delegate));
451
452   // Kick off initialization. This returns chunks from the DB synchronously.
453   pm->ForceScheduleNextUpdate(TimeDelta());
454   runner->RunPendingTasks();
455
456   // We should have an URLFetcher at this point in time.
457   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
458   ValidateUpdateFetcherRequest(url_fetcher);
459
460   // Go ahead and respond to it.
461   url_fetcher->set_status(net::URLRequestStatus());
462   url_fetcher->set_response_code(404);
463   url_fetcher->SetResponseString(std::string());
464   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
465
466   // There should now be a backup request.
467   net::TestURLFetcher* backup_url_fetcher =
468       url_fetcher_factory.GetFetcherByID(1);
469   ValidateUpdateFetcherRequest(backup_url_fetcher, kBackupHttpUrlPrefix);
470
471   // Respond to the backup unsuccessfully.
472   backup_url_fetcher->set_status(net::URLRequestStatus());
473   backup_url_fetcher->set_response_code(404);
474   backup_url_fetcher->SetResponseString(std::string());
475   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
476
477   EXPECT_TRUE(pm->IsUpdateScheduled());
478 }
479
480 // Tests what happens when there is an HTTP error response to the update
481 // request, followed by a successful response to the backup update request.
482 TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseHttpErrorBackupSuccess) {
483   scoped_refptr<base::TestSimpleTaskRunner> runner(
484       new base::TestSimpleTaskRunner());
485   base::ThreadTaskRunnerHandle runner_handler(runner);
486   net::TestURLFetcherFactory url_fetcher_factory;
487
488   testing::StrictMock<MockProtocolDelegate> test_delegate;
489   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
490   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
491       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
492                                     std::vector<SBListChunkRanges>(),
493                                     false)));
494   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
495
496   scoped_ptr<SafeBrowsingProtocolManager> pm(
497       CreateProtocolManager(&test_delegate));
498
499   // Kick off initialization. This returns chunks from the DB synchronously.
500   pm->ForceScheduleNextUpdate(TimeDelta());
501   runner->RunPendingTasks();
502
503   // We should have an URLFetcher at this point in time.
504   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
505   ValidateUpdateFetcherRequest(url_fetcher);
506
507   // Go ahead and respond to it.
508   url_fetcher->set_status(net::URLRequestStatus());
509   url_fetcher->set_response_code(404);
510   url_fetcher->SetResponseString(std::string());
511   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
512
513   // There should now be a backup request.
514   net::TestURLFetcher* backup_url_fetcher =
515       url_fetcher_factory.GetFetcherByID(1);
516   ValidateUpdateFetcherRequest(backup_url_fetcher,
517                                kBackupHttpUrlPrefix);
518
519   // Respond to the backup successfully.
520   backup_url_fetcher->set_status(net::URLRequestStatus());
521   backup_url_fetcher->set_response_code(200);
522   backup_url_fetcher->SetResponseString(std::string());
523   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
524
525   EXPECT_TRUE(pm->IsUpdateScheduled());
526 }
527
528 // Tests what happens when there is an HTTP error response to the update
529 // request, and a timeout on the backup update request.
530 TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseHttpErrorBackupTimeout) {
531   scoped_refptr<base::TestSimpleTaskRunner> runner(
532       new base::TestSimpleTaskRunner());
533   base::ThreadTaskRunnerHandle runner_handler(runner);
534   net::TestURLFetcherFactory url_fetcher_factory;
535
536   testing::StrictMock<MockProtocolDelegate> test_delegate;
537   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
538   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
539       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
540                                     std::vector<SBListChunkRanges>(),
541                                     false)));
542   EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
543
544   scoped_ptr<SafeBrowsingProtocolManager> pm(
545       CreateProtocolManager(&test_delegate));
546
547   // Kick off initialization. This returns chunks from the DB synchronously.
548   pm->ForceScheduleNextUpdate(TimeDelta());
549   runner->RunPendingTasks();
550
551   // We should have an URLFetcher at this point in time.
552   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
553   ValidateUpdateFetcherRequest(url_fetcher);
554
555   // Go ahead and respond to it.
556   url_fetcher->set_status(net::URLRequestStatus());
557   url_fetcher->set_response_code(404);
558   url_fetcher->SetResponseString(std::string());
559   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
560
561   // There should now be a backup request.
562   net::TestURLFetcher* backup_url_fetcher =
563       url_fetcher_factory.GetFetcherByID(1);
564   ValidateUpdateFetcherRequest(backup_url_fetcher, kBackupHttpUrlPrefix);
565
566   // Either one or two calls to RunPendingTasks are needed here. The first run
567   // of RunPendingTasks will run the canceled timeout task associated with
568   // the first Update request. Depending on timing, this will either directly
569   // call the timeout task from the backup request, or schedule another task
570   // to run that in the future.
571   // TODO(cbentzel): Less fragile approach.
572   runner->RunPendingTasks();
573   if (!pm->IsUpdateScheduled())
574     runner->RunPendingTasks();
575   EXPECT_TRUE(pm->IsUpdateScheduled());
576 }
577
578 // Tests what happens when there is a connection error when issuing the update
579 // request, and an error with the backup update request.
580 TEST_F(SafeBrowsingProtocolManagerTest,
581        UpdateResponseConnectionErrorBackupError) {
582   scoped_refptr<base::TestSimpleTaskRunner> runner(
583       new base::TestSimpleTaskRunner());
584   base::ThreadTaskRunnerHandle runner_handler(runner);
585   net::TestURLFetcherFactory url_fetcher_factory;
586
587   testing::StrictMock<MockProtocolDelegate> test_delegate;
588   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
589   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
590       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
591                                     std::vector<SBListChunkRanges>(),
592                                     false)));
593   EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
594
595   scoped_ptr<SafeBrowsingProtocolManager> pm(
596       CreateProtocolManager(&test_delegate));
597
598   // Kick off initialization. This returns chunks from the DB synchronously.
599   pm->ForceScheduleNextUpdate(TimeDelta());
600   runner->RunPendingTasks();
601
602   // We should have an URLFetcher at this point in time.
603   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
604   ValidateUpdateFetcherRequest(url_fetcher);
605
606   // Go ahead and respond to it.
607   url_fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
608                                                 net::ERR_CONNECTION_RESET));
609   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
610
611   // There should be a backup URLFetcher now.
612   net::TestURLFetcher* backup_url_fetcher =
613       url_fetcher_factory.GetFetcherByID(1);
614   ValidateUpdateFetcherRequest(backup_url_fetcher,
615                                kBackupConnectUrlPrefix);
616
617   // Respond to the backup unsuccessfully.
618   backup_url_fetcher->set_status(net::URLRequestStatus());
619   backup_url_fetcher->set_response_code(404);
620   backup_url_fetcher->SetResponseString(std::string());
621   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
622
623   EXPECT_TRUE(pm->IsUpdateScheduled());
624 }
625
626 // Tests what happens when there is a connection error when issuing the update
627 // request, and a successful response to the backup update request.
628 TEST_F(SafeBrowsingProtocolManagerTest,
629        UpdateResponseConnectionErrorBackupSuccess) {
630   scoped_refptr<base::TestSimpleTaskRunner> runner(
631       new base::TestSimpleTaskRunner());
632   base::ThreadTaskRunnerHandle runner_handler(runner);
633   net::TestURLFetcherFactory url_fetcher_factory;
634
635   testing::StrictMock<MockProtocolDelegate> test_delegate;
636   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
637   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
638       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
639                                     std::vector<SBListChunkRanges>(),
640                                     false)));
641   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
642
643   scoped_ptr<SafeBrowsingProtocolManager> pm(
644       CreateProtocolManager(&test_delegate));
645
646   // Kick off initialization. This returns chunks from the DB synchronously.
647   pm->ForceScheduleNextUpdate(TimeDelta());
648   runner->RunPendingTasks();
649
650   // We should have an URLFetcher at this point in time.
651   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
652   ValidateUpdateFetcherRequest(url_fetcher);
653
654   // Go ahead and respond to it.
655   url_fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
656                                                 net::ERR_CONNECTION_RESET));
657   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
658
659   // There should be a backup URLFetcher now.
660   net::TestURLFetcher* backup_url_fetcher =
661       url_fetcher_factory.GetFetcherByID(1);
662   ValidateUpdateFetcherRequest(backup_url_fetcher,
663                                kBackupConnectUrlPrefix);
664
665   // Respond to the backup unsuccessfully.
666   backup_url_fetcher->set_status(net::URLRequestStatus());
667   backup_url_fetcher->set_response_code(200);
668   backup_url_fetcher->SetResponseString(std::string());
669   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
670
671   EXPECT_TRUE(pm->IsUpdateScheduled());
672 }
673 // Tests what happens when there is a network state error when issuing the
674 // update request, and an error with the backup update request.
675 TEST_F(SafeBrowsingProtocolManagerTest,
676        UpdateResponseNetworkErrorBackupError) {
677   scoped_refptr<base::TestSimpleTaskRunner> runner(
678       new base::TestSimpleTaskRunner());
679   base::ThreadTaskRunnerHandle runner_handler(runner);
680   net::TestURLFetcherFactory url_fetcher_factory;
681
682   testing::StrictMock<MockProtocolDelegate> test_delegate;
683   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
684   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
685       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
686                                     std::vector<SBListChunkRanges>(),
687                                     false)));
688   EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
689
690   scoped_ptr<SafeBrowsingProtocolManager> pm(
691       CreateProtocolManager(&test_delegate));
692
693   // Kick off initialization. This returns chunks from the DB synchronously.
694   pm->ForceScheduleNextUpdate(TimeDelta());
695   runner->RunPendingTasks();
696
697   // We should have an URLFetcher at this point in time.
698   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
699   ValidateUpdateFetcherRequest(url_fetcher);
700
701   // Go ahead and respond to it.
702   url_fetcher->set_status(
703       net::URLRequestStatus(net::URLRequestStatus::FAILED,
704                             net::ERR_INTERNET_DISCONNECTED));
705   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
706
707   // There should be a backup URLFetcher now.
708   net::TestURLFetcher* backup_url_fetcher =
709       url_fetcher_factory.GetFetcherByID(1);
710   ValidateUpdateFetcherRequest(backup_url_fetcher,
711                                kBackupNetworkUrlPrefix);
712
713   // Respond to the backup unsuccessfully.
714   backup_url_fetcher->set_status(net::URLRequestStatus());
715   backup_url_fetcher->set_response_code(404);
716   backup_url_fetcher->SetResponseString(std::string());
717   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
718
719   EXPECT_TRUE(pm->IsUpdateScheduled());
720 }
721
722 // Tests what happens when there is a network state error when issuing the
723 // update request, and a successful response to the backup update request.
724 TEST_F(SafeBrowsingProtocolManagerTest,
725        UpdateResponseNetworkErrorBackupSuccess) {
726   scoped_refptr<base::TestSimpleTaskRunner> runner(
727       new base::TestSimpleTaskRunner());
728   base::ThreadTaskRunnerHandle runner_handler(runner);
729   net::TestURLFetcherFactory url_fetcher_factory;
730
731   testing::StrictMock<MockProtocolDelegate> test_delegate;
732   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
733   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
734       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
735                                     std::vector<SBListChunkRanges>(),
736                                     false)));
737   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
738
739   scoped_ptr<SafeBrowsingProtocolManager> pm(
740       CreateProtocolManager(&test_delegate));
741
742   // Kick off initialization. This returns chunks from the DB synchronously.
743   pm->ForceScheduleNextUpdate(TimeDelta());
744   runner->RunPendingTasks();
745
746   // We should have an URLFetcher at this point in time.
747   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
748   ValidateUpdateFetcherRequest(url_fetcher);
749
750   // Go ahead and respond to it.
751   url_fetcher->set_status(
752       net::URLRequestStatus(net::URLRequestStatus::FAILED,
753                             net::ERR_INTERNET_DISCONNECTED));
754   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
755
756   // There should be a backup URLFetcher now.
757   net::TestURLFetcher* backup_url_fetcher =
758       url_fetcher_factory.GetFetcherByID(1);
759   ValidateUpdateFetcherRequest(backup_url_fetcher,
760                                kBackupNetworkUrlPrefix);
761
762   // Respond to the backup unsuccessfully.
763   backup_url_fetcher->set_status(net::URLRequestStatus());
764   backup_url_fetcher->set_response_code(200);
765   backup_url_fetcher->SetResponseString(std::string());
766   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
767
768   EXPECT_TRUE(pm->IsUpdateScheduled());
769 }
770
771 // Tests what happens when there is a timeout before an update response.
772 TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseTimeoutBackupSuccess) {
773   scoped_refptr<base::TestSimpleTaskRunner> runner(
774       new base::TestSimpleTaskRunner());
775   base::ThreadTaskRunnerHandle runner_handler(runner);
776   net::TestURLFetcherFactory url_fetcher_factory;
777
778   testing::StrictMock<MockProtocolDelegate> test_delegate;
779   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
780   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
781       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
782                                     std::vector<SBListChunkRanges>(),
783                                     false)));
784   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
785
786   scoped_ptr<SafeBrowsingProtocolManager> pm(
787       CreateProtocolManager(&test_delegate));
788
789   // Kick off initialization. This returns chunks from the DB synchronously.
790   pm->ForceScheduleNextUpdate(TimeDelta());
791   runner->RunPendingTasks();
792
793   // We should have an URLFetcher at this point in time.
794   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
795   ValidateUpdateFetcherRequest(url_fetcher);
796
797   // The first time RunPendingTasks is called above, the update timeout timer is
798   // not handled. This call of RunPendingTasks will handle the update.
799   runner->RunPendingTasks();
800
801   // There should be a backup URLFetcher now.
802   net::TestURLFetcher* backup_url_fetcher =
803       url_fetcher_factory.GetFetcherByID(1);
804   ValidateUpdateFetcherRequest(backup_url_fetcher,
805                                kBackupConnectUrlPrefix);
806
807   // Respond to the backup unsuccessfully.
808   backup_url_fetcher->set_status(net::URLRequestStatus());
809   backup_url_fetcher->set_response_code(200);
810   backup_url_fetcher->SetResponseString(std::string());
811   backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
812
813   EXPECT_TRUE(pm->IsUpdateScheduled());
814 }
815
816 // Tests what happens when there is a reset command in the response.
817 TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseReset) {
818   scoped_refptr<base::TestSimpleTaskRunner> runner(
819       new base::TestSimpleTaskRunner());
820   base::ThreadTaskRunnerHandle runner_handler(runner);
821   net::TestURLFetcherFactory url_fetcher_factory;
822
823   testing::StrictMock<MockProtocolDelegate> test_delegate;
824   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
825   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
826       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
827                                     std::vector<SBListChunkRanges>(),
828                                     false)));
829   EXPECT_CALL(test_delegate, ResetDatabase()).Times(1);
830   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
831
832   scoped_ptr<SafeBrowsingProtocolManager> pm(
833       CreateProtocolManager(&test_delegate));
834
835   // Kick off initialization. This returns chunks from the DB synchronously.
836   pm->ForceScheduleNextUpdate(TimeDelta());
837   runner->RunPendingTasks();
838
839   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
840   ValidateUpdateFetcherRequest(url_fetcher);
841
842   // The update response is successful, and has a reset command.
843   url_fetcher->set_status(net::URLRequestStatus());
844   url_fetcher->set_response_code(200);
845   url_fetcher->SetResponseString("r:pleasereset\n");
846   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
847
848   EXPECT_TRUE(pm->IsUpdateScheduled());
849 }
850
851 // Tests a single valid update response, followed by a single redirect response
852 // that has an valid, but empty body.
853 TEST_F(SafeBrowsingProtocolManagerTest, EmptyRedirectResponse) {
854   scoped_refptr<base::TestSimpleTaskRunner> runner(
855       new base::TestSimpleTaskRunner());
856   base::ThreadTaskRunnerHandle runner_handler(runner);
857   net::TestURLFetcherFactory url_fetcher_factory;
858
859   testing::StrictMock<MockProtocolDelegate> test_delegate;
860   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
861   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
862       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
863                                     std::vector<SBListChunkRanges>(),
864                                     false)));
865   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
866
867   scoped_ptr<SafeBrowsingProtocolManager> pm(
868       CreateProtocolManager(&test_delegate));
869
870   // Kick off initialization. This returns chunks from the DB synchronously.
871   pm->ForceScheduleNextUpdate(TimeDelta());
872   runner->RunPendingTasks();
873
874   // The update response contains a single redirect command.
875   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
876   ValidateUpdateFetcherRequest(url_fetcher);
877   url_fetcher->set_status(net::URLRequestStatus());
878   url_fetcher->set_response_code(200);
879   url_fetcher->SetResponseString(
880       "i:goog-phish-shavar\n"
881       "u:redirect-server.example.com/path\n");
882   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
883
884   // The redirect response contains an empty body.
885   net::TestURLFetcher* chunk_url_fetcher =
886       url_fetcher_factory.GetFetcherByID(1);
887   ValidateRedirectFetcherRequest(
888       chunk_url_fetcher, "https://redirect-server.example.com/path");
889   chunk_url_fetcher->set_status(net::URLRequestStatus());
890   chunk_url_fetcher->set_response_code(200);
891   chunk_url_fetcher->SetResponseString(std::string());
892   chunk_url_fetcher->delegate()->OnURLFetchComplete(chunk_url_fetcher);
893
894   EXPECT_TRUE(pm->IsUpdateScheduled());
895 }
896
897 // Tests a single valid update response, followed by a single redirect response
898 // that has an invalid body.
899 TEST_F(SafeBrowsingProtocolManagerTest, InvalidRedirectResponse) {
900   scoped_refptr<base::TestSimpleTaskRunner> runner(
901       new base::TestSimpleTaskRunner());
902   base::ThreadTaskRunnerHandle runner_handler(runner);
903   net::TestURLFetcherFactory url_fetcher_factory;
904
905   testing::StrictMock<MockProtocolDelegate> test_delegate;
906   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
907   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
908       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
909                                     std::vector<SBListChunkRanges>(),
910                                     false)));
911   EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
912
913   scoped_ptr<SafeBrowsingProtocolManager> pm(
914       CreateProtocolManager(&test_delegate));
915
916   // Kick off initialization. This returns chunks from the DB synchronously.
917   pm->ForceScheduleNextUpdate(TimeDelta());
918   runner->RunPendingTasks();
919
920   // The update response contains a single redirect command.
921   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
922   ValidateUpdateFetcherRequest(url_fetcher);
923   url_fetcher->set_status(net::URLRequestStatus());
924   url_fetcher->set_response_code(200);
925   url_fetcher->SetResponseString(
926       "i:goog-phish-shavar\n"
927       "u:redirect-server.example.com/path\n");
928   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
929
930   // The redirect response contains an invalid body.
931   net::TestURLFetcher* chunk_url_fetcher =
932       url_fetcher_factory.GetFetcherByID(1);
933   ValidateRedirectFetcherRequest(
934       chunk_url_fetcher, "https://redirect-server.example.com/path");
935   chunk_url_fetcher->set_status(net::URLRequestStatus());
936   chunk_url_fetcher->set_response_code(200);
937   chunk_url_fetcher->SetResponseString("THIS IS AN INVALID RESPONSE");
938   chunk_url_fetcher->delegate()->OnURLFetchComplete(chunk_url_fetcher);
939
940   EXPECT_TRUE(pm->IsUpdateScheduled());
941 }
942
943 // Tests a single valid update response, followed by a single redirect response
944 // containing chunks.
945 TEST_F(SafeBrowsingProtocolManagerTest, SingleRedirectResponseWithChunks) {
946   scoped_refptr<base::TestSimpleTaskRunner> runner(
947       new base::TestSimpleTaskRunner());
948   base::ThreadTaskRunnerHandle runner_handler(runner);
949   net::TestURLFetcherFactory url_fetcher_factory;
950
951   testing::StrictMock<MockProtocolDelegate> test_delegate;
952   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
953   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
954       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
955                                     std::vector<SBListChunkRanges>(),
956                                     false)));
957   EXPECT_CALL(test_delegate, AddChunks("goog-phish-shavar", _, _)).WillOnce(
958       Invoke(HandleAddChunks));
959   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
960
961   scoped_ptr<SafeBrowsingProtocolManager> pm(
962       CreateProtocolManager(&test_delegate));
963
964   // Kick off initialization. This returns chunks from the DB synchronously.
965   pm->ForceScheduleNextUpdate(TimeDelta());
966   runner->RunPendingTasks();
967
968   // The update response contains a single redirect command.
969   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
970   ValidateUpdateFetcherRequest(url_fetcher);
971   url_fetcher->set_status(net::URLRequestStatus());
972   url_fetcher->set_response_code(200);
973   url_fetcher->SetResponseString(
974       "i:goog-phish-shavar\n"
975       "u:redirect-server.example.com/path\n");
976   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
977
978   // The redirect response contains a single chunk.
979   net::TestURLFetcher* chunk_url_fetcher =
980       url_fetcher_factory.GetFetcherByID(1);
981   ValidateRedirectFetcherRequest(
982       chunk_url_fetcher, "https://redirect-server.example.com/path");
983   chunk_url_fetcher->set_status(net::URLRequestStatus());
984   chunk_url_fetcher->set_response_code(200);
985   chunk_url_fetcher->SetResponseString(
986       "a:4:4:9\n"
987       "host\1fdaf");
988   chunk_url_fetcher->delegate()->OnURLFetchComplete(chunk_url_fetcher);
989
990   EXPECT_FALSE(pm->IsUpdateScheduled());
991
992   // The AddChunksCallback needs to be invoked.
993   runner->RunPendingTasks();
994
995   EXPECT_TRUE(pm->IsUpdateScheduled());
996 }
997
998 // Tests a single valid update response, followed by multiple redirect responses
999 // containing chunks.
1000 TEST_F(SafeBrowsingProtocolManagerTest, MultipleRedirectResponsesWithChunks) {
1001   scoped_refptr<base::TestSimpleTaskRunner> runner(
1002       new base::TestSimpleTaskRunner());
1003   base::ThreadTaskRunnerHandle runner_handler(runner);
1004   net::TestURLFetcherFactory url_fetcher_factory;
1005
1006   testing::StrictMock<MockProtocolDelegate> test_delegate;
1007   EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
1008   EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
1009       Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
1010                                     std::vector<SBListChunkRanges>(),
1011                                     false)));
1012   EXPECT_CALL(test_delegate, AddChunks("goog-phish-shavar", _, _)).
1013       WillRepeatedly(Invoke(HandleAddChunks));
1014   EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
1015
1016   scoped_ptr<SafeBrowsingProtocolManager> pm(
1017       CreateProtocolManager(&test_delegate));
1018
1019   // Kick off initialization. This returns chunks from the DB synchronously.
1020   pm->ForceScheduleNextUpdate(TimeDelta());
1021   runner->RunPendingTasks();
1022
1023   // The update response contains multiple redirect commands.
1024   net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
1025   ValidateUpdateFetcherRequest(url_fetcher);
1026   url_fetcher->set_status(net::URLRequestStatus());
1027   url_fetcher->set_response_code(200);
1028   url_fetcher->SetResponseString(
1029       "i:goog-phish-shavar\n"
1030       "u:redirect-server.example.com/one\n"
1031       "u:redirect-server.example.com/two\n");
1032   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
1033
1034   // The first redirect response contains a single chunk.
1035   net::TestURLFetcher* first_chunk_url_fetcher =
1036       url_fetcher_factory.GetFetcherByID(1);
1037   ValidateRedirectFetcherRequest(
1038       first_chunk_url_fetcher, "https://redirect-server.example.com/one");
1039   first_chunk_url_fetcher->set_status(net::URLRequestStatus());
1040   first_chunk_url_fetcher->set_response_code(200);
1041   first_chunk_url_fetcher->SetResponseString(
1042       "a:4:4:9\n"
1043       "host\1aaaa");
1044   first_chunk_url_fetcher->delegate()->OnURLFetchComplete(
1045       first_chunk_url_fetcher);
1046
1047   // Invoke the AddChunksCallback to trigger the second request.
1048   runner->RunPendingTasks();
1049
1050   EXPECT_FALSE(pm->IsUpdateScheduled());
1051
1052   // The second redirect response contains a single chunk.
1053   net::TestURLFetcher* second_chunk_url_fetcher =
1054       url_fetcher_factory.GetFetcherByID(2);
1055   ValidateRedirectFetcherRequest(
1056       second_chunk_url_fetcher, "https://redirect-server.example.com/two");
1057   second_chunk_url_fetcher->set_status(net::URLRequestStatus());
1058   second_chunk_url_fetcher->set_response_code(200);
1059   second_chunk_url_fetcher->SetResponseString(
1060       "a:5:4:9\n"
1061       "host\1bbbb");
1062   second_chunk_url_fetcher->delegate()->OnURLFetchComplete(
1063       second_chunk_url_fetcher);
1064
1065   EXPECT_FALSE(pm->IsUpdateScheduled());
1066
1067   // Invoke the AddChunksCallback to finish the update.
1068   runner->RunPendingTasks();
1069
1070   EXPECT_TRUE(pm->IsUpdateScheduled());
1071 }