Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / cookies / cookie_monster_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 #include "net/cookies/cookie_store_unittest.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram.h"
17 #include "base/metrics/histogram_samples.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/string_split.h"
21 #include "base/strings/string_tokenizer.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/threading/thread.h"
24 #include "base/time/time.h"
25 #include "net/cookies/canonical_cookie.h"
26 #include "net/cookies/cookie_constants.h"
27 #include "net/cookies/cookie_monster.h"
28 #include "net/cookies/cookie_monster_store_test.h"  // For CookieStore mock
29 #include "net/cookies/cookie_util.h"
30 #include "net/cookies/parsed_cookie.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "url/gurl.h"
34
35 namespace net {
36
37 using base::Time;
38 using base::TimeDelta;
39
40 namespace {
41
42 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and
43 // brethren) with this one, and remove the 'New' prefix.
44 class NewMockPersistentCookieStore
45     : public CookieMonster::PersistentCookieStore {
46  public:
47   MOCK_METHOD1(Load, void(const LoadedCallback& loaded_callback));
48   MOCK_METHOD2(LoadCookiesForKey, void(const std::string& key,
49                                        const LoadedCallback& loaded_callback));
50   MOCK_METHOD1(AddCookie, void(const CanonicalCookie& cc));
51   MOCK_METHOD1(UpdateCookieAccessTime, void(const CanonicalCookie& cc));
52   MOCK_METHOD1(DeleteCookie, void(const CanonicalCookie& cc));
53   virtual void Flush(const base::Closure& callback) {
54     if (!callback.is_null())
55       base::MessageLoop::current()->PostTask(FROM_HERE, callback);
56   }
57   MOCK_METHOD0(SetForceKeepSessionState, void());
58
59  private:
60   virtual ~NewMockPersistentCookieStore() {}
61 };
62
63 const char* kTopLevelDomainPlus1 = "http://www.harvard.edu";
64 const char* kTopLevelDomainPlus2 = "http://www.math.harvard.edu";
65 const char* kTopLevelDomainPlus2Secure = "https://www.math.harvard.edu";
66 const char* kTopLevelDomainPlus3 =
67     "http://www.bourbaki.math.harvard.edu";
68 const char* kOtherDomain = "http://www.mit.edu";
69 const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle";
70
71 class GetCookieListCallback : public CookieCallback {
72  public:
73   GetCookieListCallback() {}
74   explicit GetCookieListCallback(Thread* run_in_thread)
75       : CookieCallback(run_in_thread) {}
76
77   void Run(const CookieList& cookies) {
78     cookies_ = cookies;
79     CallbackEpilogue();
80   }
81
82   const CookieList& cookies() { return cookies_; }
83
84  private:
85   CookieList cookies_;
86 };
87
88 struct CookieMonsterTestTraits {
89   static scoped_refptr<CookieStore> Create() {
90     return new CookieMonster(NULL, NULL);
91   }
92
93   static const bool is_cookie_monster              = true;
94   static const bool supports_http_only             = true;
95   static const bool supports_non_dotted_domains    = true;
96   static const bool supports_trailing_dots         = true;
97   static const bool filters_schemes                = true;
98   static const bool has_path_prefix_bug            = false;
99   static const int creation_time_granularity_in_ms = 0;
100 };
101
102 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster,
103                               CookieStoreTest,
104                               CookieMonsterTestTraits);
105
106 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster,
107                               MultiThreadedCookieStoreTest,
108                               CookieMonsterTestTraits);
109
110 class CookieMonsterTest : public CookieStoreTest<CookieMonsterTestTraits> {
111  protected:
112
113   CookieList GetAllCookies(CookieMonster* cm) {
114     DCHECK(cm);
115     GetCookieListCallback callback;
116     cm->GetAllCookiesAsync(
117         base::Bind(&GetCookieListCallback::Run,
118                    base::Unretained(&callback)));
119     RunFor(kTimeout);
120     EXPECT_TRUE(callback.did_run());
121     return callback.cookies();
122   }
123
124   CookieList GetAllCookiesForURL(CookieMonster* cm,
125                                  const GURL& url) {
126     DCHECK(cm);
127     GetCookieListCallback callback;
128     cm->GetAllCookiesForURLAsync(
129         url, base::Bind(&GetCookieListCallback::Run,
130                         base::Unretained(&callback)));
131     RunFor(kTimeout);
132     EXPECT_TRUE(callback.did_run());
133     return callback.cookies();
134   }
135
136   CookieList GetAllCookiesForURLWithOptions(CookieMonster* cm,
137                                             const GURL& url,
138                                             const CookieOptions& options) {
139     DCHECK(cm);
140     GetCookieListCallback callback;
141     cm->GetAllCookiesForURLWithOptionsAsync(
142         url, options, base::Bind(&GetCookieListCallback::Run,
143                                  base::Unretained(&callback)));
144     RunFor(kTimeout);
145     EXPECT_TRUE(callback.did_run());
146     return callback.cookies();
147   }
148
149   bool SetCookieWithDetails(CookieMonster* cm,
150                             const GURL& url,
151                             const std::string& name,
152                             const std::string& value,
153                             const std::string& domain,
154                             const std::string& path,
155                             const base::Time& expiration_time,
156                             bool secure,
157                             bool http_only,
158                             CookiePriority priority) {
159     DCHECK(cm);
160     ResultSavingCookieCallback<bool> callback;
161     cm->SetCookieWithDetailsAsync(
162         url, name, value, domain, path, expiration_time, secure, http_only,
163         priority,
164         base::Bind(
165             &ResultSavingCookieCallback<bool>::Run,
166             base::Unretained(&callback)));
167     RunFor(kTimeout);
168     EXPECT_TRUE(callback.did_run());
169     return callback.result();
170   }
171
172   int DeleteAll(CookieMonster*cm) {
173     DCHECK(cm);
174     ResultSavingCookieCallback<int> callback;
175     cm->DeleteAllAsync(
176         base::Bind(
177             &ResultSavingCookieCallback<int>::Run,
178             base::Unretained(&callback)));
179     RunFor(kTimeout);
180     EXPECT_TRUE(callback.did_run());
181     return callback.result();
182   }
183
184   int DeleteAllCreatedBetween(CookieMonster*cm,
185                               const base::Time& delete_begin,
186                               const base::Time& delete_end) {
187     DCHECK(cm);
188     ResultSavingCookieCallback<int> callback;
189     cm->DeleteAllCreatedBetweenAsync(
190         delete_begin, delete_end,
191         base::Bind(
192             &ResultSavingCookieCallback<int>::Run,
193             base::Unretained(&callback)));
194     RunFor(kTimeout);
195     EXPECT_TRUE(callback.did_run());
196     return callback.result();
197   }
198
199   int DeleteAllCreatedBetweenForHost(CookieMonster* cm,
200                                      const base::Time delete_begin,
201                                      const base::Time delete_end,
202                                      const GURL& url) {
203     DCHECK(cm);
204     ResultSavingCookieCallback<int> callback;
205     cm->DeleteAllCreatedBetweenForHostAsync(
206         delete_begin, delete_end, url,
207         base::Bind(
208             &ResultSavingCookieCallback<int>::Run,
209             base::Unretained(&callback)));
210     RunFor(kTimeout);
211     EXPECT_TRUE(callback.did_run());
212     return callback.result();
213   }
214
215   int DeleteAllForHost(CookieMonster* cm,
216                        const GURL& url) {
217     DCHECK(cm);
218     ResultSavingCookieCallback<int> callback;
219     cm->DeleteAllForHostAsync(
220         url, base::Bind(&ResultSavingCookieCallback<int>::Run,
221                         base::Unretained(&callback)));
222     RunFor(kTimeout);
223     EXPECT_TRUE(callback.did_run());
224     return callback.result();
225   }
226
227   bool DeleteCanonicalCookie(CookieMonster* cm, const CanonicalCookie& cookie) {
228     DCHECK(cm);
229     ResultSavingCookieCallback<bool> callback;
230     cm->DeleteCanonicalCookieAsync(
231         cookie,
232         base::Bind(&ResultSavingCookieCallback<bool>::Run,
233                    base::Unretained(&callback)));
234     RunFor(kTimeout);
235     EXPECT_TRUE(callback.did_run());
236     return callback.result();
237   }
238
239   // Helper for DeleteAllForHost test; repopulates CM with same layout
240   // each time.
241   void PopulateCmForDeleteAllForHost(scoped_refptr<CookieMonster> cm) {
242     GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1);
243     GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2);
244     GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure);
245     GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3);
246     GURL url_other(kOtherDomain);
247
248     DeleteAll(cm.get());
249
250     // Static population for probe:
251     //    * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
252     //    * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
253     //    * http_only cookie (w.c.b.a)
254     //    * Two secure cookies (.c.b.a, w.c.b.a)
255     //    * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
256     //    * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
257
258     // Domain cookies
259     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
260                                            url_top_level_domain_plus_1,
261                                            "dom_1",
262                                            "X",
263                                            ".harvard.edu",
264                                            "/",
265                                            base::Time(),
266                                            false,
267                                            false,
268                                            COOKIE_PRIORITY_DEFAULT));
269     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
270                                            url_top_level_domain_plus_2,
271                                            "dom_2",
272                                            "X",
273                                            ".math.harvard.edu",
274                                            "/",
275                                            base::Time(),
276                                            false,
277                                            false,
278                                            COOKIE_PRIORITY_DEFAULT));
279     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
280                                            url_top_level_domain_plus_3,
281                                            "dom_3",
282                                            "X",
283                                            ".bourbaki.math.harvard.edu",
284                                            "/",
285                                            base::Time(),
286                                            false,
287                                            false,
288                                            COOKIE_PRIORITY_DEFAULT));
289
290     // Host cookies
291     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
292                                            url_top_level_domain_plus_1,
293                                            "host_1",
294                                            "X",
295                                            std::string(),
296                                            "/",
297                                            base::Time(),
298                                            false,
299                                            false,
300                                            COOKIE_PRIORITY_DEFAULT));
301     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
302                                            url_top_level_domain_plus_2,
303                                            "host_2",
304                                            "X",
305                                            std::string(),
306                                            "/",
307                                            base::Time(),
308                                            false,
309                                            false,
310                                            COOKIE_PRIORITY_DEFAULT));
311     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
312                                            url_top_level_domain_plus_3,
313                                            "host_3",
314                                            "X",
315                                            std::string(),
316                                            "/",
317                                            base::Time(),
318                                            false,
319                                            false,
320                                            COOKIE_PRIORITY_DEFAULT));
321
322     // Http_only cookie
323     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
324                                            url_top_level_domain_plus_2,
325                                            "httpo_check",
326                                            "X",
327                                            std::string(),
328                                            "/",
329                                            base::Time(),
330                                            false,
331                                            true,
332                                            COOKIE_PRIORITY_DEFAULT));
333
334     // Secure cookies
335     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
336                                            url_top_level_domain_plus_2_secure,
337                                            "sec_dom",
338                                            "X",
339                                            ".math.harvard.edu",
340                                            "/",
341                                            base::Time(),
342                                            true,
343                                            false,
344                                            COOKIE_PRIORITY_DEFAULT));
345     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
346                                            url_top_level_domain_plus_2_secure,
347                                            "sec_host",
348                                            "X",
349                                            std::string(),
350                                            "/",
351                                            base::Time(),
352                                            true,
353                                            false,
354                                            COOKIE_PRIORITY_DEFAULT));
355
356     // Domain path cookies
357     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
358                                            url_top_level_domain_plus_2,
359                                            "dom_path_1",
360                                            "X",
361                                            ".math.harvard.edu",
362                                            "/dir1",
363                                            base::Time(),
364                                            false,
365                                            false,
366                                            COOKIE_PRIORITY_DEFAULT));
367     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
368                                            url_top_level_domain_plus_2,
369                                            "dom_path_2",
370                                            "X",
371                                            ".math.harvard.edu",
372                                            "/dir1/dir2",
373                                            base::Time(),
374                                            false,
375                                            false,
376                                            COOKIE_PRIORITY_DEFAULT));
377
378     // Host path cookies
379     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
380                                            url_top_level_domain_plus_2,
381                                            "host_path_1",
382                                            "X",
383                                            std::string(),
384                                            "/dir1",
385                                            base::Time(),
386                                            false,
387                                            false,
388                                            COOKIE_PRIORITY_DEFAULT));
389     EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
390                                            url_top_level_domain_plus_2,
391                                            "host_path_2",
392                                            "X",
393                                            std::string(),
394                                            "/dir1/dir2",
395                                            base::Time(),
396                                            false,
397                                            false,
398                                            COOKIE_PRIORITY_DEFAULT));
399
400     EXPECT_EQ(13U, this->GetAllCookies(cm.get()).size());
401   }
402
403   Time GetFirstCookieAccessDate(CookieMonster* cm) {
404     const CookieList all_cookies(this->GetAllCookies(cm));
405     return all_cookies.front().LastAccessDate();
406   }
407
408   bool FindAndDeleteCookie(CookieMonster* cm,
409                            const std::string& domain,
410                            const std::string& name) {
411     CookieList cookies = this->GetAllCookies(cm);
412     for (CookieList::iterator it = cookies.begin();
413          it != cookies.end(); ++it)
414       if (it->Domain() == domain && it->Name() == name)
415         return this->DeleteCanonicalCookie(cm, *it);
416     return false;
417   }
418
419   int CountInString(const std::string& str, char c) {
420     return std::count(str.begin(), str.end(), c);
421   }
422
423   void TestHostGarbageCollectHelper() {
424     int domain_max_cookies = CookieMonster::kDomainMaxCookies;
425     int domain_purge_cookies = CookieMonster::kDomainPurgeCookies;
426     const int more_than_enough_cookies =
427         (domain_max_cookies + domain_purge_cookies) * 2;
428     // Add a bunch of cookies on a single host, should purge them.
429     {
430       scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
431       for (int i = 0; i < more_than_enough_cookies; ++i) {
432         std::string cookie = base::StringPrintf("a%03d=b", i);
433         EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie));
434         std::string cookies = this->GetCookies(cm.get(), url_google_);
435         // Make sure we find it in the cookies.
436         EXPECT_NE(cookies.find(cookie), std::string::npos);
437         // Count the number of cookies.
438         EXPECT_LE(CountInString(cookies, '='), domain_max_cookies);
439       }
440     }
441
442     // Add a bunch of cookies on multiple hosts within a single eTLD.
443     // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
444     // between them.  We shouldn't go above kDomainMaxCookies for both together.
445     GURL url_google_specific(kUrlGoogleSpecific);
446     {
447       scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
448       for (int i = 0; i < more_than_enough_cookies; ++i) {
449         std::string cookie_general = base::StringPrintf("a%03d=b", i);
450         EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie_general));
451         std::string cookie_specific = base::StringPrintf("c%03d=b", i);
452         EXPECT_TRUE(SetCookie(cm.get(), url_google_specific, cookie_specific));
453         std::string cookies_general = this->GetCookies(cm.get(), url_google_);
454         EXPECT_NE(cookies_general.find(cookie_general), std::string::npos);
455         std::string cookies_specific =
456             this->GetCookies(cm.get(), url_google_specific);
457         EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos);
458         EXPECT_LE((CountInString(cookies_general, '=') +
459                    CountInString(cookies_specific, '=')),
460                   domain_max_cookies);
461       }
462       // After all this, there should be at least
463       // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
464       std::string cookies_general = this->GetCookies(cm.get(), url_google_);
465       std::string cookies_specific =
466           this->GetCookies(cm.get(), url_google_specific);
467       int total_cookies = (CountInString(cookies_general, '=') +
468                            CountInString(cookies_specific, '='));
469       EXPECT_GE(total_cookies, domain_max_cookies - domain_purge_cookies);
470       EXPECT_LE(total_cookies, domain_max_cookies);
471     }
472   }
473
474   CookiePriority CharToPriority(char ch) {
475     switch (ch) {
476       case 'L':
477         return COOKIE_PRIORITY_LOW;
478       case 'M':
479         return COOKIE_PRIORITY_MEDIUM;
480       case 'H':
481         return COOKIE_PRIORITY_HIGH;
482     }
483     NOTREACHED();
484     return COOKIE_PRIORITY_DEFAULT;
485   }
486
487   // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
488   // priorities specified by |coded_priority_str|, and tests priority-aware
489   // domain cookie eviction.
490   // |coded_priority_str| specifies a run-length-encoded string of priorities.
491   // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
492   // from least- to most-recently accessed) insertion of 2 medium-priority
493   // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4
494   // high-priority cookies.
495   // Within each priority, only the least-accessed cookies should be evicted.
496   // Thus, to describe expected suriving cookies, it suffices to specify the
497   // expected population of surviving cookies per priority, i.e.,
498   // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
499   void TestPriorityCookieCase(CookieMonster* cm,
500                               const std::string& coded_priority_str,
501                               size_t expected_low_count,
502                               size_t expected_medium_count,
503                               size_t expected_high_count) {
504     DeleteAll(cm);
505     int next_cookie_id = 0;
506     std::vector<CookiePriority> priority_list;
507     std::vector<int> id_list[3];  // Indexed by CookiePriority.
508
509     // Parse |coded_priority_str| and add cookies.
510     std::vector<std::string> priority_tok_list;
511     base::SplitString(coded_priority_str, ' ', &priority_tok_list);
512     for (std::vector<std::string>::iterator it = priority_tok_list.begin();
513          it != priority_tok_list.end(); ++it) {
514       size_t len = it->length();
515       DCHECK_NE(len, 0U);
516       // Take last character as priority.
517       CookiePriority priority = CharToPriority((*it)[len - 1]);
518       std::string priority_str = CookiePriorityToString(priority);
519       // The rest of the string (possibly empty) specifies repetition.
520       int rep = 1;
521       if (!it->empty()) {
522         bool result = base::StringToInt(
523             base::StringPiece(it->begin(), it->end() - 1), &rep);
524         DCHECK(result);
525       }
526       for (; rep > 0; --rep, ++next_cookie_id) {
527         std::string cookie = base::StringPrintf(
528             "a%d=b;priority=%s", next_cookie_id, priority_str.c_str());
529         EXPECT_TRUE(SetCookie(cm, url_google_, cookie));
530         priority_list.push_back(priority);
531         id_list[priority].push_back(next_cookie_id);
532       }
533     }
534
535     int num_cookies = static_cast<int>(priority_list.size());
536     std::vector<int> surviving_id_list[3];  // Indexed by CookiePriority.
537
538     // Parse the list of cookies
539     std::string cookie_str = this->GetCookies(cm, url_google_);
540     std::vector<std::string> cookie_tok_list;
541     base::SplitString(cookie_str, ';', &cookie_tok_list);
542     for (std::vector<std::string>::iterator it = cookie_tok_list.begin();
543          it != cookie_tok_list.end(); ++it) {
544       // Assuming *it is "a#=b", so extract and parse "#" portion.
545       int id = -1;
546       bool result = base::StringToInt(
547           base::StringPiece(it->begin() + 1, it->end() - 2), &id);
548       DCHECK(result);
549       DCHECK_GE(id, 0);
550       DCHECK_LT(id, num_cookies);
551       surviving_id_list[priority_list[id]].push_back(id);
552     }
553
554     // Validate each priority.
555     size_t expected_count[3] = {
556       expected_low_count, expected_medium_count, expected_high_count
557     };
558     for (int i = 0; i < 3; ++i) {
559       DCHECK_LE(surviving_id_list[i].size(), id_list[i].size());
560       EXPECT_EQ(expected_count[i], surviving_id_list[i].size());
561       // Verify that the remaining cookies are the most recent among those
562       // with the same priorities.
563       if (expected_count[i] == surviving_id_list[i].size()) {
564         std::sort(surviving_id_list[i].begin(), surviving_id_list[i].end());
565         EXPECT_TRUE(std::equal(surviving_id_list[i].begin(),
566                                surviving_id_list[i].end(),
567                                id_list[i].end() - expected_count[i]));
568       }
569     }
570   }
571
572   void TestPriorityAwareGarbageCollectHelper() {
573     // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
574     DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies);
575     DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
576               CookieMonster::kDomainPurgeCookies);
577     DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow);
578     DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium);
579     DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh);
580
581     scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
582
583     // Each test case adds 181 cookies, so 31 cookies are evicted.
584     // Cookie same priority, repeated for each priority.
585     TestPriorityCookieCase(cm.get(), "181L", 150U, 0U, 0U);
586     TestPriorityCookieCase(cm.get(), "181M", 0U, 150U, 0U);
587     TestPriorityCookieCase(cm.get(), "181H", 0U, 0U, 150U);
588
589     // Pairwise scenarios.
590     // Round 1 => none; round2 => 31M; round 3 => none.
591     TestPriorityCookieCase(cm.get(), "10H 171M", 0U, 140U, 10U);
592     // Round 1 => 10L; round2 => 21M; round 3 => none.
593     TestPriorityCookieCase(cm.get(), "141M 40L", 30U, 120U, 0U);
594     // Round 1 => none; round2 => none; round 3 => 31H.
595     TestPriorityCookieCase(cm.get(), "101H 80M", 0U, 80U, 70U);
596
597     // For {low, medium} priorities right on quota, different orders.
598     // Round 1 => 1L; round 2 => none, round3 => 30L.
599     TestPriorityCookieCase(cm.get(), "31L 50M 100H", 0U, 50U, 100U);
600     // Round 1 => none; round 2 => 1M, round3 => 30M.
601     TestPriorityCookieCase(cm.get(), "51M 100H 30L", 30U, 20U, 100U);
602     // Round 1 => none; round 2 => none; round3 => 31H.
603     TestPriorityCookieCase(cm.get(), "101H 50M 30L", 30U, 50U, 70U);
604
605     // Round 1 => 10L; round 2 => 10M; round3 => 11H.
606     TestPriorityCookieCase(cm.get(), "81H 60M 40L", 30U, 50U, 70U);
607
608     // More complex scenarios.
609     // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
610     TestPriorityCookieCase(cm.get(), "21H 60M 40L 60H", 30U, 50U, 70U);
611     // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
612     TestPriorityCookieCase(
613         cm.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U, 21U);
614     // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
615     TestPriorityCookieCase(cm.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U);
616     // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
617     TestPriorityCookieCase(cm.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U);
618     // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
619     TestPriorityCookieCase(cm.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U);
620   }
621
622   // Function for creating a CM with a number of cookies in it,
623   // no store (and hence no ability to affect access time).
624   CookieMonster* CreateMonsterForGC(int num_cookies) {
625     CookieMonster* cm(new CookieMonster(NULL, NULL));
626     for (int i = 0; i < num_cookies; i++) {
627       SetCookie(cm, GURL(base::StringPrintf("http://h%05d.izzle", i)), "a=1");
628     }
629     return cm;
630   }
631 };
632
633 // TODO(erikwright): Replace the other callbacks and synchronous helper methods
634 // in this test suite with these Mocks.
635 template<typename T, typename C> class MockCookieCallback {
636  public:
637   C AsCallback() {
638     return base::Bind(&T::Invoke, base::Unretained(static_cast<T*>(this)));
639   }
640 };
641
642 class MockGetCookiesCallback
643   : public MockCookieCallback<MockGetCookiesCallback,
644                               CookieStore::GetCookiesCallback> {
645  public:
646   MOCK_METHOD1(Invoke, void(const std::string& cookies));
647 };
648
649 class MockSetCookiesCallback
650   : public MockCookieCallback<MockSetCookiesCallback,
651                               CookieStore::SetCookiesCallback> {
652  public:
653   MOCK_METHOD1(Invoke, void(bool success));
654 };
655
656 class MockClosure
657   : public MockCookieCallback<MockClosure, base::Closure> {
658  public:
659   MOCK_METHOD0(Invoke, void(void));
660 };
661
662 class MockGetCookieListCallback
663   : public MockCookieCallback<MockGetCookieListCallback,
664                               CookieMonster::GetCookieListCallback> {
665  public:
666   MOCK_METHOD1(Invoke, void(const CookieList& cookies));
667 };
668
669 class MockDeleteCallback
670   : public MockCookieCallback<MockDeleteCallback,
671                               CookieMonster::DeleteCallback> {
672  public:
673   MOCK_METHOD1(Invoke, void(int num_deleted));
674 };
675
676 class MockDeleteCookieCallback
677   : public MockCookieCallback<MockDeleteCookieCallback,
678                               CookieMonster::DeleteCookieCallback> {
679  public:
680   MOCK_METHOD1(Invoke, void(bool success));
681 };
682
683 struct CookiesInputInfo {
684   const GURL url;
685   const std::string name;
686   const std::string value;
687   const std::string domain;
688   const std::string path;
689   const base::Time expiration_time;
690   bool secure;
691   bool http_only;
692   CookiePriority priority;
693 };
694
695 ACTION(QuitCurrentMessageLoop) {
696   base::MessageLoop::current()->PostTask(FROM_HERE,
697                                          base::MessageLoop::QuitClosure());
698 }
699
700 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
701 // rename these, removing the 'Action' suffix.
702 ACTION_P4(DeleteCookieAction, cookie_monster, url, name, callback) {
703   cookie_monster->DeleteCookieAsync(url, name, callback->AsCallback());
704 }
705 ACTION_P3(GetCookiesAction, cookie_monster, url, callback) {
706   cookie_monster->GetCookiesWithOptionsAsync(
707       url, CookieOptions(), callback->AsCallback());
708 }
709 ACTION_P4(SetCookieAction, cookie_monster, url, cookie_line, callback) {
710   cookie_monster->SetCookieWithOptionsAsync(
711       url, cookie_line, CookieOptions(), callback->AsCallback());
712 }
713 ACTION_P4(DeleteAllCreatedBetweenAction,
714           cookie_monster, delete_begin, delete_end, callback) {
715   cookie_monster->DeleteAllCreatedBetweenAsync(
716       delete_begin, delete_end, callback->AsCallback());
717 }
718 ACTION_P3(SetCookieWithDetailsAction, cookie_monster, cc, callback) {
719   cookie_monster->SetCookieWithDetailsAsync(
720       cc.url, cc.name, cc.value, cc.domain, cc.path, cc.expiration_time,
721       cc.secure, cc.http_only, cc.priority,
722       callback->AsCallback());
723 }
724
725 ACTION_P2(GetAllCookiesAction, cookie_monster, callback) {
726   cookie_monster->GetAllCookiesAsync(callback->AsCallback());
727 }
728
729 ACTION_P3(DeleteAllForHostAction, cookie_monster, url, callback) {
730   cookie_monster->DeleteAllForHostAsync(url, callback->AsCallback());
731 }
732
733 ACTION_P3(DeleteCanonicalCookieAction, cookie_monster, cookie, callback) {
734   cookie_monster->DeleteCanonicalCookieAsync(cookie, callback->AsCallback());
735 }
736
737 ACTION_P2(DeleteAllAction, cookie_monster, callback) {
738   cookie_monster->DeleteAllAsync(callback->AsCallback());
739 }
740
741 ACTION_P3(GetAllCookiesForUrlWithOptionsAction, cookie_monster, url, callback) {
742   cookie_monster->GetAllCookiesForURLWithOptionsAsync(
743       url, CookieOptions(), callback->AsCallback());
744 }
745
746 ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) {
747   cookie_monster->GetAllCookiesForURLAsync(url, callback->AsCallback());
748 }
749
750 ACTION_P(PushCallbackAction, callback_vector) {
751   callback_vector->push(arg1);
752 }
753
754 ACTION_P2(DeleteSessionCookiesAction, cookie_monster, callback) {
755   cookie_monster->DeleteSessionCookiesAsync(callback->AsCallback());
756 }
757
758 }  // namespace
759
760 // This test suite verifies the task deferral behaviour of the CookieMonster.
761 // Specifically, for each asynchronous method, verify that:
762 // 1. invoking it on an uninitialized cookie store causes the store to begin
763 //    chain-loading its backing data or loading data for a specific domain key
764 //    (eTLD+1).
765 // 2. The initial invocation does not complete until the loading completes.
766 // 3. Invocations after the loading has completed complete immediately.
767 class DeferredCookieTaskTest : public CookieMonsterTest {
768  protected:
769   DeferredCookieTaskTest() {
770     persistent_store_ = new NewMockPersistentCookieStore();
771     cookie_monster_ = new CookieMonster(persistent_store_.get(), NULL);
772   }
773
774   // Defines a cookie to be returned from PersistentCookieStore::Load
775   void DeclareLoadedCookie(const std::string& key,
776                            const std::string& cookie_line,
777                            const base::Time& creation_time) {
778     AddCookieToList(key, cookie_line, creation_time, &loaded_cookies_);
779   }
780
781   // Runs the message loop, waiting until PersistentCookieStore::Load is called.
782   // Call CompleteLoadingAndWait to cause the load to complete.
783   void WaitForLoadCall() {
784     RunFor(kTimeout);
785
786     // Verify that PeristentStore::Load was called.
787     testing::Mock::VerifyAndClear(persistent_store_.get());
788   }
789
790   // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
791   // and PersistentCookieStore::Load completion callback and waits
792   // until the message loop is quit.
793   void CompleteLoadingAndWait() {
794     while (!loaded_for_key_callbacks_.empty()) {
795       loaded_for_key_callbacks_.front().Run(loaded_cookies_);
796       loaded_cookies_.clear();
797       loaded_for_key_callbacks_.pop();
798     }
799
800     loaded_callback_.Run(loaded_cookies_);
801     RunFor(kTimeout);
802   }
803
804   // Performs the provided action, expecting it to cause a call to
805   // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call
806   // is received.
807   void BeginWith(testing::Action<void(void)> action) {
808     EXPECT_CALL(*this, Begin()).WillOnce(action);
809     ExpectLoadCall();
810     Begin();
811   }
812
813   void BeginWithForDomainKey(std::string key,
814                              testing::Action<void(void)> action) {
815     EXPECT_CALL(*this, Begin()).WillOnce(action);
816     ExpectLoadCall();
817     ExpectLoadForKeyCall(key, false);
818     Begin();
819   }
820
821   // Declares an expectation that PersistentCookieStore::Load will be called,
822   // saving the provided callback and sending a quit to the message loop.
823   void ExpectLoadCall() {
824     EXPECT_CALL(*persistent_store_.get(), Load(testing::_))
825         .WillOnce(testing::DoAll(testing::SaveArg<0>(&loaded_callback_),
826                                  QuitCurrentMessageLoop()));
827   }
828
829   // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
830   // will be called, saving the provided callback and sending a quit to the
831   // message loop.
832   void ExpectLoadForKeyCall(std::string key, bool quit_queue) {
833     if (quit_queue)
834       EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_))
835           .WillOnce(
836                testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_),
837                               QuitCurrentMessageLoop()));
838     else
839       EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_))
840           .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_));
841   }
842
843   // Invokes the initial action.
844   MOCK_METHOD0(Begin, void(void));
845
846   // Returns the CookieMonster instance under test.
847   CookieMonster& cookie_monster() { return *cookie_monster_.get(); }
848
849  private:
850   // Declares that mock expectations in this test suite are strictly ordered.
851   testing::InSequence in_sequence_;
852   // Holds cookies to be returned from PersistentCookieStore::Load or
853   // PersistentCookieStore::LoadCookiesForKey.
854   std::vector<CanonicalCookie*> loaded_cookies_;
855   // Stores the callback passed from the CookieMonster to the
856   // PersistentCookieStore::Load
857   CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_;
858   // Stores the callback passed from the CookieMonster to the
859   // PersistentCookieStore::LoadCookiesForKey
860   std::queue<CookieMonster::PersistentCookieStore::LoadedCallback>
861     loaded_for_key_callbacks_;
862
863   // Stores the CookieMonster under test.
864   scoped_refptr<CookieMonster> cookie_monster_;
865   // Stores the mock PersistentCookieStore.
866   scoped_refptr<NewMockPersistentCookieStore> persistent_store_;
867 };
868
869 TEST_F(DeferredCookieTaskTest, DeferredGetCookies) {
870   DeclareLoadedCookie("www.google.izzle",
871                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
872                       Time::Now() + TimeDelta::FromDays(3));
873
874   MockGetCookiesCallback get_cookies_callback;
875
876   BeginWithForDomainKey("google.izzle", GetCookiesAction(
877       &cookie_monster(), url_google_, &get_cookies_callback));
878
879   WaitForLoadCall();
880
881   EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
882       GetCookiesAction(&cookie_monster(), url_google_, &get_cookies_callback));
883   EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
884       QuitCurrentMessageLoop());
885
886   CompleteLoadingAndWait();
887 }
888
889 TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {
890   MockSetCookiesCallback set_cookies_callback;
891
892   BeginWithForDomainKey("google.izzle", SetCookieAction(
893       &cookie_monster(), url_google_, "A=B", &set_cookies_callback));
894
895   WaitForLoadCall();
896
897   EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
898       SetCookieAction(
899           &cookie_monster(), url_google_, "X=Y", &set_cookies_callback));
900   EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
901       QuitCurrentMessageLoop());
902
903   CompleteLoadingAndWait();
904 }
905
906 TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) {
907   MockClosure delete_cookie_callback;
908
909   BeginWithForDomainKey("google.izzle", DeleteCookieAction(
910       &cookie_monster(), url_google_, "A", &delete_cookie_callback));
911
912   WaitForLoadCall();
913
914   EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce(
915       DeleteCookieAction(
916           &cookie_monster(), url_google_, "X", &delete_cookie_callback));
917   EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce(
918       QuitCurrentMessageLoop());
919
920   CompleteLoadingAndWait();
921 }
922
923 TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) {
924   MockSetCookiesCallback set_cookies_callback;
925
926   CookiesInputInfo cookie_info = {
927     url_google_foo_, "A", "B", std::string(), "/foo",
928     base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
929   };
930   BeginWithForDomainKey("google.izzle", SetCookieWithDetailsAction(
931       &cookie_monster(), cookie_info, &set_cookies_callback));
932
933   WaitForLoadCall();
934
935   CookiesInputInfo cookie_info_exp = {
936     url_google_foo_, "A", "B", std::string(), "/foo",
937     base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
938   };
939   EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
940       SetCookieWithDetailsAction(
941           &cookie_monster(), cookie_info_exp, &set_cookies_callback));
942   EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
943       QuitCurrentMessageLoop());
944
945   CompleteLoadingAndWait();
946 }
947
948 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) {
949   DeclareLoadedCookie("www.google.izzle",
950                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
951                       Time::Now() + TimeDelta::FromDays(3));
952
953   MockGetCookieListCallback get_cookie_list_callback;
954
955   BeginWith(GetAllCookiesAction(
956       &cookie_monster(), &get_cookie_list_callback));
957
958   WaitForLoadCall();
959
960   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
961       GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback));
962   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
963       QuitCurrentMessageLoop());
964
965   CompleteLoadingAndWait();
966 }
967
968 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) {
969   DeclareLoadedCookie("www.google.izzle",
970                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
971                       Time::Now() + TimeDelta::FromDays(3));
972
973   MockGetCookieListCallback get_cookie_list_callback;
974
975   BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlAction(
976       &cookie_monster(), url_google_, &get_cookie_list_callback));
977
978   WaitForLoadCall();
979
980   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
981       GetAllCookiesForUrlAction(
982           &cookie_monster(), url_google_, &get_cookie_list_callback));
983   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
984       QuitCurrentMessageLoop());
985
986   CompleteLoadingAndWait();
987 }
988
989 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) {
990   DeclareLoadedCookie("www.google.izzle",
991                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
992                       Time::Now() + TimeDelta::FromDays(3));
993
994   MockGetCookieListCallback get_cookie_list_callback;
995
996   BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
997       &cookie_monster(), url_google_, &get_cookie_list_callback));
998
999   WaitForLoadCall();
1000
1001   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
1002       GetAllCookiesForUrlWithOptionsAction(
1003           &cookie_monster(), url_google_, &get_cookie_list_callback));
1004   EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
1005       QuitCurrentMessageLoop());
1006
1007   CompleteLoadingAndWait();
1008 }
1009
1010 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCookies) {
1011   MockDeleteCallback delete_callback;
1012
1013   BeginWith(DeleteAllAction(
1014       &cookie_monster(), &delete_callback));
1015
1016   WaitForLoadCall();
1017
1018   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1019       DeleteAllAction(&cookie_monster(), &delete_callback));
1020   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1021       QuitCurrentMessageLoop());
1022
1023   CompleteLoadingAndWait();
1024 }
1025
1026 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedBetweenCookies) {
1027   MockDeleteCallback delete_callback;
1028
1029   BeginWith(DeleteAllCreatedBetweenAction(
1030       &cookie_monster(), base::Time(), base::Time::Now(), &delete_callback));
1031
1032   WaitForLoadCall();
1033
1034   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1035       DeleteAllCreatedBetweenAction(
1036           &cookie_monster(), base::Time(), base::Time::Now(),
1037           &delete_callback));
1038   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1039       QuitCurrentMessageLoop());
1040
1041   CompleteLoadingAndWait();
1042 }
1043
1044 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllForHostCookies) {
1045   MockDeleteCallback delete_callback;
1046
1047   BeginWithForDomainKey("google.izzle", DeleteAllForHostAction(
1048       &cookie_monster(), url_google_, &delete_callback));
1049
1050   WaitForLoadCall();
1051
1052   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1053       DeleteAllForHostAction(
1054           &cookie_monster(), url_google_, &delete_callback));
1055   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1056       QuitCurrentMessageLoop());
1057
1058   CompleteLoadingAndWait();
1059 }
1060
1061 TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) {
1062   std::vector<CanonicalCookie*> cookies;
1063   CanonicalCookie cookie = BuildCanonicalCookie(
1064       "www.google.com", "X=1; path=/", base::Time::Now());
1065
1066   MockDeleteCookieCallback delete_cookie_callback;
1067
1068   BeginWith(DeleteCanonicalCookieAction(
1069       &cookie_monster(), cookie, &delete_cookie_callback));
1070
1071   WaitForLoadCall();
1072
1073   EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce(
1074       DeleteCanonicalCookieAction(
1075       &cookie_monster(), cookie, &delete_cookie_callback));
1076   EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce(
1077       QuitCurrentMessageLoop());
1078
1079   CompleteLoadingAndWait();
1080 }
1081
1082 TEST_F(DeferredCookieTaskTest, DeferredDeleteSessionCookies) {
1083   MockDeleteCallback delete_callback;
1084
1085   BeginWith(DeleteSessionCookiesAction(
1086       &cookie_monster(), &delete_callback));
1087
1088   WaitForLoadCall();
1089
1090   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1091       DeleteSessionCookiesAction(&cookie_monster(), &delete_callback));
1092   EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1093       QuitCurrentMessageLoop());
1094
1095   CompleteLoadingAndWait();
1096 }
1097
1098 // Verify that a series of queued tasks are executed in order upon loading of
1099 // the backing store and that new tasks received while the queued tasks are
1100 // being dispatched go to the end of the queue.
1101 TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {
1102   DeclareLoadedCookie("www.google.izzle",
1103                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1104                       Time::Now() + TimeDelta::FromDays(3));
1105
1106   MockGetCookiesCallback get_cookies_callback;
1107   MockSetCookiesCallback set_cookies_callback;
1108   MockGetCookiesCallback get_cookies_callback_deferred;
1109
1110   EXPECT_CALL(*this, Begin()).WillOnce(testing::DoAll(
1111       GetCookiesAction(
1112           &cookie_monster(), url_google_, &get_cookies_callback),
1113       SetCookieAction(
1114           &cookie_monster(), url_google_, "A=B", &set_cookies_callback)));
1115   ExpectLoadCall();
1116   ExpectLoadForKeyCall("google.izzle", false);
1117   Begin();
1118
1119   WaitForLoadCall();
1120   EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
1121       GetCookiesAction(
1122           &cookie_monster(), url_google_, &get_cookies_callback_deferred));
1123   EXPECT_CALL(set_cookies_callback, Invoke(true));
1124   EXPECT_CALL(get_cookies_callback_deferred, Invoke("A=B; X=1")).WillOnce(
1125       QuitCurrentMessageLoop());
1126
1127   CompleteLoadingAndWait();
1128 }
1129
1130 TEST_F(CookieMonsterTest, TestCookieDeleteAll) {
1131   scoped_refptr<MockPersistentCookieStore> store(
1132       new MockPersistentCookieStore);
1133   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1134   CookieOptions options;
1135   options.set_include_httponly();
1136
1137   EXPECT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
1138   EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1139
1140   EXPECT_TRUE(
1141       SetCookieWithOptions(cm.get(), url_google_, "C=D; httponly", options));
1142   EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm.get(), url_google_, options));
1143
1144   EXPECT_EQ(2, DeleteAll(cm.get()));
1145   EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
1146   EXPECT_EQ(0u, store->commands().size());
1147
1148   // Create a persistent cookie.
1149   EXPECT_TRUE(SetCookie(
1150       cm.get(),
1151       url_google_,
1152       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1153   ASSERT_EQ(1u, store->commands().size());
1154   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1155
1156   EXPECT_EQ(1, DeleteAll(cm.get()));  // sync_to_store = true.
1157   ASSERT_EQ(2u, store->commands().size());
1158   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1159
1160   EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
1161 }
1162
1163 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) {
1164   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1165   Time now = Time::Now();
1166
1167   // Nothing has been added so nothing should be deleted.
1168   EXPECT_EQ(
1169       0,
1170       DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99), Time()));
1171
1172   // Create 3 cookies with creation date of today, yesterday and the day before.
1173   EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-0=Now", now));
1174   EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-1=Yesterday",
1175                                             now - TimeDelta::FromDays(1)));
1176   EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-2=DayBefore",
1177                                             now - TimeDelta::FromDays(2)));
1178   EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-3=ThreeDays",
1179                                             now - TimeDelta::FromDays(3)));
1180   EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-7=LastWeek",
1181                                             now - TimeDelta::FromDays(7)));
1182
1183   // Try to delete threedays and the daybefore.
1184   EXPECT_EQ(2,
1185             DeleteAllCreatedBetween(cm.get(),
1186                                     now - TimeDelta::FromDays(3),
1187                                     now - TimeDelta::FromDays(1)));
1188
1189   // Try to delete yesterday, also make sure that delete_end is not
1190   // inclusive.
1191   EXPECT_EQ(
1192       1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(2), now));
1193
1194   // Make sure the delete_begin is inclusive.
1195   EXPECT_EQ(
1196       1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(7), now));
1197
1198   // Delete the last (now) item.
1199   EXPECT_EQ(1, DeleteAllCreatedBetween(cm.get(), Time(), Time()));
1200
1201   // Really make sure everything is gone.
1202   EXPECT_EQ(0, DeleteAll(cm.get()));
1203 }
1204
1205 static const int kAccessDelayMs = kLastAccessThresholdMilliseconds + 20;
1206
1207 TEST_F(CookieMonsterTest, TestLastAccess) {
1208   scoped_refptr<CookieMonster> cm(
1209       new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1210
1211   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1212   const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
1213
1214   // Reading the cookie again immediately shouldn't update the access date,
1215   // since we're inside the threshold.
1216   EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1217   EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1218
1219   // Reading after a short wait should update the access date.
1220   base::PlatformThread::Sleep(
1221       base::TimeDelta::FromMilliseconds(kAccessDelayMs));
1222   EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1223   EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1224 }
1225
1226 TEST_F(CookieMonsterTest, TestHostGarbageCollection) {
1227   TestHostGarbageCollectHelper();
1228 }
1229
1230 TEST_F(CookieMonsterTest, TestPriorityAwareGarbageCollection) {
1231   TestPriorityAwareGarbageCollectHelper();
1232 }
1233
1234 TEST_F(CookieMonsterTest, TestDeleteSingleCookie) {
1235   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1236
1237   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1238   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
1239   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
1240   EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
1241
1242   EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
1243   EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1244
1245   EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
1246   EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1247 }
1248
1249 TEST_F(CookieMonsterTest, SetCookieableSchemes) {
1250   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1251   scoped_refptr<CookieMonster> cm_foo(new CookieMonster(NULL, NULL));
1252
1253   // Only cm_foo should allow foo:// cookies.
1254   const char* kSchemes[] = {"foo"};
1255   cm_foo->SetCookieableSchemes(kSchemes, 1);
1256
1257   GURL foo_url("foo://host/path");
1258   GURL http_url("http://host/path");
1259
1260   EXPECT_TRUE(SetCookie(cm.get(), http_url, "x=1"));
1261   EXPECT_FALSE(SetCookie(cm.get(), foo_url, "x=1"));
1262   EXPECT_TRUE(SetCookie(cm_foo.get(), foo_url, "x=1"));
1263   EXPECT_FALSE(SetCookie(cm_foo.get(), http_url, "x=1"));
1264 }
1265
1266 TEST_F(CookieMonsterTest, GetAllCookiesForURL) {
1267   scoped_refptr<CookieMonster> cm(
1268       new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1269
1270   // Create an httponly cookie.
1271   CookieOptions options;
1272   options.set_include_httponly();
1273
1274   EXPECT_TRUE(
1275       SetCookieWithOptions(cm.get(), url_google_, "A=B; httponly", options));
1276   EXPECT_TRUE(SetCookieWithOptions(
1277       cm.get(), url_google_, "C=D; domain=.google.izzle", options));
1278   EXPECT_TRUE(SetCookieWithOptions(cm.get(),
1279                                    url_google_secure_,
1280                                    "E=F; domain=.google.izzle; secure",
1281                                    options));
1282
1283   const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
1284
1285   base::PlatformThread::Sleep(
1286       base::TimeDelta::FromMilliseconds(kAccessDelayMs));
1287
1288   // Check cookies for url.
1289   CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
1290   CookieList::iterator it = cookies.begin();
1291
1292   ASSERT_TRUE(it != cookies.end());
1293   EXPECT_EQ("www.google.izzle", it->Domain());
1294   EXPECT_EQ("A", it->Name());
1295
1296   ASSERT_TRUE(++it != cookies.end());
1297   EXPECT_EQ(".google.izzle", it->Domain());
1298   EXPECT_EQ("C", it->Name());
1299
1300   ASSERT_TRUE(++it == cookies.end());
1301
1302   // Check cookies for url excluding http-only cookies.
1303   cookies =
1304       GetAllCookiesForURLWithOptions(cm.get(), url_google_, CookieOptions());
1305   it = cookies.begin();
1306
1307   ASSERT_TRUE(it != cookies.end());
1308   EXPECT_EQ(".google.izzle", it->Domain());
1309   EXPECT_EQ("C", it->Name());
1310
1311   ASSERT_TRUE(++it == cookies.end());
1312
1313   // Test secure cookies.
1314   cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
1315   it = cookies.begin();
1316
1317   ASSERT_TRUE(it != cookies.end());
1318   EXPECT_EQ("www.google.izzle", it->Domain());
1319   EXPECT_EQ("A", it->Name());
1320
1321   ASSERT_TRUE(++it != cookies.end());
1322   EXPECT_EQ(".google.izzle", it->Domain());
1323   EXPECT_EQ("C", it->Name());
1324
1325   ASSERT_TRUE(++it != cookies.end());
1326   EXPECT_EQ(".google.izzle", it->Domain());
1327   EXPECT_EQ("E", it->Name());
1328
1329   ASSERT_TRUE(++it == cookies.end());
1330
1331   // Reading after a short wait should not update the access date.
1332   EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1333 }
1334
1335 TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
1336   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1337   CookieOptions options;
1338
1339   EXPECT_TRUE(SetCookieWithOptions(
1340       cm.get(), url_google_foo_, "A=B; path=/foo;", options));
1341   EXPECT_TRUE(SetCookieWithOptions(
1342       cm.get(), url_google_bar_, "C=D; path=/bar;", options));
1343   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "E=F;", options));
1344
1345   CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
1346   CookieList::iterator it = cookies.begin();
1347
1348   ASSERT_TRUE(it != cookies.end());
1349   EXPECT_EQ("A", it->Name());
1350   EXPECT_EQ("/foo", it->Path());
1351
1352   ASSERT_TRUE(++it != cookies.end());
1353   EXPECT_EQ("E", it->Name());
1354   EXPECT_EQ("/", it->Path());
1355
1356   ASSERT_TRUE(++it == cookies.end());
1357
1358   cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
1359   it = cookies.begin();
1360
1361   ASSERT_TRUE(it != cookies.end());
1362   EXPECT_EQ("C", it->Name());
1363   EXPECT_EQ("/bar", it->Path());
1364
1365   ASSERT_TRUE(++it != cookies.end());
1366   EXPECT_EQ("E", it->Name());
1367   EXPECT_EQ("/", it->Path());
1368
1369   ASSERT_TRUE(++it == cookies.end());
1370 }
1371
1372 TEST_F(CookieMonsterTest, DeleteCookieByName) {
1373   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1374
1375   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A1; path=/"));
1376   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A2; path=/foo"));
1377   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A3; path=/bar"));
1378   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B1; path=/"));
1379   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B2; path=/foo"));
1380   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/bar"));
1381
1382   DeleteCookie(cm.get(), GURL(std::string(kUrlGoogle) + "/foo/bar"), "A");
1383
1384   CookieList cookies = GetAllCookies(cm.get());
1385   size_t expected_size = 4;
1386   EXPECT_EQ(expected_size, cookies.size());
1387   for (CookieList::iterator it = cookies.begin();
1388        it != cookies.end(); ++it) {
1389     EXPECT_NE("A1", it->Value());
1390     EXPECT_NE("A2", it->Value());
1391   }
1392 }
1393
1394 TEST_F(CookieMonsterTest, InitializeFromCookieMonster) {
1395   scoped_refptr<CookieMonster> cm_1(new CookieMonster(NULL, NULL));
1396   CookieOptions options;
1397
1398   EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_foo_,
1399                                                "A1=B; path=/foo;",
1400                                                options));
1401   EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_bar_,
1402                                                "A2=D; path=/bar;",
1403                                                options));
1404   EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_,
1405                                                "A3=F;",
1406                                                options));
1407
1408   CookieList cookies_1 = GetAllCookies(cm_1.get());
1409   scoped_refptr<CookieMonster> cm_2(new CookieMonster(NULL, NULL));
1410   ASSERT_TRUE(cm_2->InitializeFrom(cookies_1));
1411   CookieList cookies_2 = GetAllCookies(cm_2.get());
1412
1413   size_t expected_size = 3;
1414   EXPECT_EQ(expected_size, cookies_2.size());
1415
1416   CookieList::iterator it = cookies_2.begin();
1417
1418   ASSERT_TRUE(it != cookies_2.end());
1419   EXPECT_EQ("A1", it->Name());
1420   EXPECT_EQ("/foo", it->Path());
1421
1422   ASSERT_TRUE(++it != cookies_2.end());
1423   EXPECT_EQ("A2", it->Name());
1424   EXPECT_EQ("/bar", it->Path());
1425
1426   ASSERT_TRUE(++it != cookies_2.end());
1427   EXPECT_EQ("A3", it->Name());
1428   EXPECT_EQ("/", it->Path());
1429 }
1430
1431 // Tests importing from a persistent cookie store that contains duplicate
1432 // equivalent cookies. This situation should be handled by removing the
1433 // duplicate cookie (both from the in-memory cache, and from the backing store).
1434 //
1435 // This is a regression test for: http://crbug.com/17855.
1436 TEST_F(CookieMonsterTest, DontImportDuplicateCookies) {
1437   scoped_refptr<MockPersistentCookieStore> store(
1438       new MockPersistentCookieStore);
1439
1440   // We will fill some initial cookies into the PersistentCookieStore,
1441   // to simulate a database with 4 duplicates.  Note that we need to
1442   // be careful not to have any duplicate creation times at all (as it's a
1443   // violation of a CookieMonster invariant) even if Time::Now() doesn't
1444   // move between calls.
1445   std::vector<CanonicalCookie*> initial_cookies;
1446
1447   // Insert 4 cookies with name "X" on path "/", with varying creation
1448   // dates. We expect only the most recent one to be preserved following
1449   // the import.
1450
1451   AddCookieToList("www.google.com",
1452                   "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1453                   Time::Now() + TimeDelta::FromDays(3),
1454                   &initial_cookies);
1455
1456   AddCookieToList("www.google.com",
1457                   "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1458                   Time::Now() + TimeDelta::FromDays(1),
1459                   &initial_cookies);
1460
1461   // ===> This one is the WINNER (biggest creation time).  <====
1462   AddCookieToList("www.google.com",
1463                   "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1464                   Time::Now() + TimeDelta::FromDays(4),
1465                   &initial_cookies);
1466
1467   AddCookieToList("www.google.com",
1468                   "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1469                   Time::Now(),
1470                   &initial_cookies);
1471
1472   // Insert 2 cookies with name "X" on path "/2", with varying creation
1473   // dates. We expect only the most recent one to be preserved the import.
1474
1475   // ===> This one is the WINNER (biggest creation time).  <====
1476   AddCookieToList("www.google.com",
1477                   "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1478                   Time::Now() + TimeDelta::FromDays(9),
1479                   &initial_cookies);
1480
1481   AddCookieToList("www.google.com",
1482                   "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1483                   Time::Now() + TimeDelta::FromDays(2),
1484                   &initial_cookies);
1485
1486   // Insert 1 cookie with name "Y" on path "/".
1487   AddCookieToList("www.google.com",
1488                   "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1489                   Time::Now() + TimeDelta::FromDays(10),
1490                   &initial_cookies);
1491
1492   // Inject our initial cookies into the mock PersistentCookieStore.
1493   store->SetLoadExpectation(true, initial_cookies);
1494
1495   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1496
1497   // Verify that duplicates were not imported for path "/".
1498   // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1499   EXPECT_EQ("X=3; Y=a", GetCookies(cm.get(), GURL("http://www.google.com/")));
1500
1501   // Verify that same-named cookie on a different path ("/x2") didn't get
1502   // messed up.
1503   EXPECT_EQ("X=a1; X=3; Y=a",
1504             GetCookies(cm.get(), GURL("http://www.google.com/2/x")));
1505
1506   // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1507   ASSERT_EQ(4u, store->commands().size());
1508   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type);
1509   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1510   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
1511   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
1512 }
1513
1514 // Tests importing from a persistent cookie store that contains cookies
1515 // with duplicate creation times.  This situation should be handled by
1516 // dropping the cookies before insertion/visibility to user.
1517 //
1518 // This is a regression test for: http://crbug.com/43188.
1519 TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) {
1520   scoped_refptr<MockPersistentCookieStore> store(
1521       new MockPersistentCookieStore);
1522
1523   Time now(Time::Now());
1524   Time earlier(now - TimeDelta::FromDays(1));
1525
1526   // Insert 8 cookies, four with the current time as creation times, and
1527   // four with the earlier time as creation times.  We should only get
1528   // two cookies remaining, but which two (other than that there should
1529   // be one from each set) will be random.
1530   std::vector<CanonicalCookie*> initial_cookies;
1531   AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies);
1532   AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies);
1533   AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies);
1534   AddCookieToList("www.google.com", "X=4; path=/", now, &initial_cookies);
1535
1536   AddCookieToList("www.google.com", "Y=1; path=/", earlier, &initial_cookies);
1537   AddCookieToList("www.google.com", "Y=2; path=/", earlier, &initial_cookies);
1538   AddCookieToList("www.google.com", "Y=3; path=/", earlier, &initial_cookies);
1539   AddCookieToList("www.google.com", "Y=4; path=/", earlier, &initial_cookies);
1540
1541   // Inject our initial cookies into the mock PersistentCookieStore.
1542   store->SetLoadExpectation(true, initial_cookies);
1543
1544   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1545
1546   CookieList list(GetAllCookies(cm.get()));
1547   EXPECT_EQ(2U, list.size());
1548   // Confirm that we have one of each.
1549   std::string name1(list[0].Name());
1550   std::string name2(list[1].Name());
1551   EXPECT_TRUE(name1 == "X" || name2 == "X");
1552   EXPECT_TRUE(name1 == "Y" || name2 == "Y");
1553   EXPECT_NE(name1, name2);
1554 }
1555
1556 TEST_F(CookieMonsterTest, CookieMonsterDelegate) {
1557   scoped_refptr<MockPersistentCookieStore> store(
1558       new MockPersistentCookieStore);
1559   scoped_refptr<MockCookieMonsterDelegate> delegate(
1560       new MockCookieMonsterDelegate);
1561   scoped_refptr<CookieMonster> cm(
1562       new CookieMonster(store.get(), delegate.get()));
1563
1564   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1565   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
1566   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
1567   EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
1568   ASSERT_EQ(3u, delegate->changes().size());
1569   EXPECT_FALSE(delegate->changes()[0].second);
1570   EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1571   EXPECT_EQ("A", delegate->changes()[0].first.Name());
1572   EXPECT_EQ("B", delegate->changes()[0].first.Value());
1573   EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
1574   EXPECT_FALSE(delegate->changes()[1].second);
1575   EXPECT_EQ("C", delegate->changes()[1].first.Name());
1576   EXPECT_EQ("D", delegate->changes()[1].first.Value());
1577   EXPECT_EQ(url_google_.host(), delegate->changes()[2].first.Domain());
1578   EXPECT_FALSE(delegate->changes()[2].second);
1579   EXPECT_EQ("E", delegate->changes()[2].first.Name());
1580   EXPECT_EQ("F", delegate->changes()[2].first.Value());
1581   delegate->reset();
1582
1583   EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
1584   EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1585   ASSERT_EQ(1u, delegate->changes().size());
1586   EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1587   EXPECT_TRUE(delegate->changes()[0].second);
1588   EXPECT_EQ("C", delegate->changes()[0].first.Name());
1589   EXPECT_EQ("D", delegate->changes()[0].first.Value());
1590   delegate->reset();
1591
1592   EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
1593   EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1594   EXPECT_EQ(0u, delegate->changes().size());
1595
1596   // Insert a cookie "a" for path "/path1"
1597   EXPECT_TRUE(SetCookie(cm.get(),
1598                         url_google_,
1599                         "a=val1; path=/path1; "
1600                         "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1601   ASSERT_EQ(1u, store->commands().size());
1602   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1603   ASSERT_EQ(1u, delegate->changes().size());
1604   EXPECT_FALSE(delegate->changes()[0].second);
1605   EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1606   EXPECT_EQ("a", delegate->changes()[0].first.Name());
1607   EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1608   delegate->reset();
1609
1610   // Insert a cookie "a" for path "/path1", that is httponly. This should
1611   // overwrite the non-http-only version.
1612   CookieOptions allow_httponly;
1613   allow_httponly.set_include_httponly();
1614   EXPECT_TRUE(SetCookieWithOptions(cm.get(),
1615                                    url_google_,
1616                                    "a=val2; path=/path1; httponly; "
1617                                    "expires=Mon, 18-Apr-22 22:50:14 GMT",
1618                                    allow_httponly));
1619   ASSERT_EQ(3u, store->commands().size());
1620   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1621   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
1622   ASSERT_EQ(2u, delegate->changes().size());
1623   EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1624   EXPECT_TRUE(delegate->changes()[0].second);
1625   EXPECT_EQ("a", delegate->changes()[0].first.Name());
1626   EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1627   EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
1628   EXPECT_FALSE(delegate->changes()[1].second);
1629   EXPECT_EQ("a", delegate->changes()[1].first.Name());
1630   EXPECT_EQ("val2", delegate->changes()[1].first.Value());
1631   delegate->reset();
1632 }
1633
1634 TEST_F(CookieMonsterTest, SetCookieWithDetails) {
1635   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1636
1637   EXPECT_TRUE(SetCookieWithDetails(cm.get(),
1638                                    url_google_foo_,
1639                                    "A",
1640                                    "B",
1641                                    std::string(),
1642                                    "/foo",
1643                                    base::Time(),
1644                                    false,
1645                                    false,
1646                                    COOKIE_PRIORITY_DEFAULT));
1647   EXPECT_TRUE(SetCookieWithDetails(cm.get(),
1648                                    url_google_bar_,
1649                                    "C",
1650                                    "D",
1651                                    "google.izzle",
1652                                    "/bar",
1653                                    base::Time(),
1654                                    false,
1655                                    true,
1656                                    COOKIE_PRIORITY_DEFAULT));
1657   EXPECT_TRUE(SetCookieWithDetails(cm.get(),
1658                                    url_google_,
1659                                    "E",
1660                                    "F",
1661                                    std::string(),
1662                                    std::string(),
1663                                    base::Time(),
1664                                    true,
1665                                    false,
1666                                    COOKIE_PRIORITY_DEFAULT));
1667
1668   // Test that malformed attributes fail to set the cookie.
1669   EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1670                                     url_google_foo_,
1671                                     " A",
1672                                     "B",
1673                                     std::string(),
1674                                     "/foo",
1675                                     base::Time(),
1676                                     false,
1677                                     false,
1678                                     COOKIE_PRIORITY_DEFAULT));
1679   EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1680                                     url_google_foo_,
1681                                     "A;",
1682                                     "B",
1683                                     std::string(),
1684                                     "/foo",
1685                                     base::Time(),
1686                                     false,
1687                                     false,
1688                                     COOKIE_PRIORITY_DEFAULT));
1689   EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1690                                     url_google_foo_,
1691                                     "A=",
1692                                     "B",
1693                                     std::string(),
1694                                     "/foo",
1695                                     base::Time(),
1696                                     false,
1697                                     false,
1698                                     COOKIE_PRIORITY_DEFAULT));
1699   EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1700                                     url_google_foo_,
1701                                     "A",
1702                                     "B",
1703                                     "google.ozzzzzzle",
1704                                     "foo",
1705                                     base::Time(),
1706                                     false,
1707                                     false,
1708                                     COOKIE_PRIORITY_DEFAULT));
1709   EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1710                                     url_google_foo_,
1711                                     "A=",
1712                                     "B",
1713                                     std::string(),
1714                                     "foo",
1715                                     base::Time(),
1716                                     false,
1717                                     false,
1718                                     COOKIE_PRIORITY_DEFAULT));
1719
1720   CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
1721   CookieList::iterator it = cookies.begin();
1722
1723   ASSERT_TRUE(it != cookies.end());
1724   EXPECT_EQ("A", it->Name());
1725   EXPECT_EQ("B", it->Value());
1726   EXPECT_EQ("www.google.izzle", it->Domain());
1727   EXPECT_EQ("/foo", it->Path());
1728   EXPECT_FALSE(it->IsPersistent());
1729   EXPECT_FALSE(it->IsSecure());
1730   EXPECT_FALSE(it->IsHttpOnly());
1731
1732   ASSERT_TRUE(++it == cookies.end());
1733
1734   cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
1735   it = cookies.begin();
1736
1737   ASSERT_TRUE(it != cookies.end());
1738   EXPECT_EQ("C", it->Name());
1739   EXPECT_EQ("D", it->Value());
1740   EXPECT_EQ(".google.izzle", it->Domain());
1741   EXPECT_EQ("/bar", it->Path());
1742   EXPECT_FALSE(it->IsSecure());
1743   EXPECT_TRUE(it->IsHttpOnly());
1744
1745   ASSERT_TRUE(++it == cookies.end());
1746
1747   cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
1748   it = cookies.begin();
1749
1750   ASSERT_TRUE(it != cookies.end());
1751   EXPECT_EQ("E", it->Name());
1752   EXPECT_EQ("F", it->Value());
1753   EXPECT_EQ("/", it->Path());
1754   EXPECT_EQ("www.google.izzle", it->Domain());
1755   EXPECT_TRUE(it->IsSecure());
1756   EXPECT_FALSE(it->IsHttpOnly());
1757
1758   ASSERT_TRUE(++it == cookies.end());
1759 }
1760
1761 TEST_F(CookieMonsterTest, DeleteAllForHost) {
1762   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1763
1764   // Test probes:
1765   //    * Non-secure URL, mid-level (http://w.c.b.a)
1766   //    * Secure URL, mid-level (https://w.c.b.a)
1767   //    * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1768   // All three tests should nuke only the midlevel host cookie,
1769   // the http_only cookie, the host secure cookie, and the two host
1770   // path cookies.  http_only, secure, and paths are ignored by
1771   // this call, and domain cookies arent touched.
1772   PopulateCmForDeleteAllForHost(cm);
1773   EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1774             GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1775   EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1776             GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1777   EXPECT_EQ("dom_1=X; host_1=X",
1778             GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1779   EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1780             "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1781             GetCookies(cm.get(),
1782                        GURL(kTopLevelDomainPlus2Secure +
1783                             std::string("/dir1/dir2/xxx"))));
1784
1785   EXPECT_EQ(5, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2)));
1786   EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1787
1788   EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1789             GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1790   EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1791             GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1792   EXPECT_EQ("dom_1=X; host_1=X",
1793             GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1794   EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1795             GetCookies(cm.get(),
1796                        GURL(kTopLevelDomainPlus2Secure +
1797                             std::string("/dir1/dir2/xxx"))));
1798
1799   PopulateCmForDeleteAllForHost(cm);
1800   EXPECT_EQ(5, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1801   EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1802
1803   EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1804             GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1805   EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1806             GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1807   EXPECT_EQ("dom_1=X; host_1=X",
1808             GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1809   EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1810             GetCookies(cm.get(),
1811                        GURL(kTopLevelDomainPlus2Secure +
1812                             std::string("/dir1/dir2/xxx"))));
1813
1814   PopulateCmForDeleteAllForHost(cm);
1815   EXPECT_EQ(5,
1816             DeleteAllForHost(
1817                 cm.get(),
1818                 GURL(kTopLevelDomainPlus2Secure + std::string("/dir1/xxx"))));
1819   EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1820
1821   EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1822             GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1823   EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1824             GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1825   EXPECT_EQ("dom_1=X; host_1=X",
1826             GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1827   EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1828             GetCookies(cm.get(),
1829                        GURL(kTopLevelDomainPlus2Secure +
1830                             std::string("/dir1/dir2/xxx"))));
1831 }
1832
1833 TEST_F(CookieMonsterTest, UniqueCreationTime) {
1834   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1835   CookieOptions options;
1836
1837   // Add in three cookies through every public interface to the
1838   // CookieMonster and confirm that none of them have duplicate
1839   // creation times.
1840
1841   // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1842   // are not included as they aren't going to be public for very much
1843   // longer.
1844
1845   // SetCookie, SetCookieWithOptions, SetCookieWithDetails
1846
1847   SetCookie(cm.get(), url_google_, "SetCookie1=A");
1848   SetCookie(cm.get(), url_google_, "SetCookie2=A");
1849   SetCookie(cm.get(), url_google_, "SetCookie3=A");
1850
1851   SetCookieWithOptions(
1852       cm.get(), url_google_, "setCookieWithOptions1=A", options);
1853   SetCookieWithOptions(
1854       cm.get(), url_google_, "setCookieWithOptions2=A", options);
1855   SetCookieWithOptions(
1856       cm.get(), url_google_, "setCookieWithOptions3=A", options);
1857
1858   SetCookieWithDetails(cm.get(),
1859                        url_google_,
1860                        "setCookieWithDetails1",
1861                        "A",
1862                        ".google.com",
1863                        "/",
1864                        Time(),
1865                        false,
1866                        false,
1867                        COOKIE_PRIORITY_DEFAULT);
1868   SetCookieWithDetails(cm.get(),
1869                        url_google_,
1870                        "setCookieWithDetails2",
1871                        "A",
1872                        ".google.com",
1873                        "/",
1874                        Time(),
1875                        false,
1876                        false,
1877                        COOKIE_PRIORITY_DEFAULT);
1878   SetCookieWithDetails(cm.get(),
1879                        url_google_,
1880                        "setCookieWithDetails3",
1881                        "A",
1882                        ".google.com",
1883                        "/",
1884                        Time(),
1885                        false,
1886                        false,
1887                        COOKIE_PRIORITY_DEFAULT);
1888
1889   // Now we check
1890   CookieList cookie_list(GetAllCookies(cm.get()));
1891   typedef std::map<int64, CanonicalCookie> TimeCookieMap;
1892   TimeCookieMap check_map;
1893   for (CookieList::const_iterator it = cookie_list.begin();
1894        it != cookie_list.end(); it++) {
1895     const int64 creation_date = it->CreationDate().ToInternalValue();
1896     TimeCookieMap::const_iterator
1897         existing_cookie_it(check_map.find(creation_date));
1898     EXPECT_TRUE(existing_cookie_it == check_map.end())
1899         << "Cookie " << it->Name() << " has same creation date ("
1900         << it->CreationDate().ToInternalValue()
1901         << ") as previously entered cookie "
1902         << existing_cookie_it->second.Name();
1903
1904     if (existing_cookie_it == check_map.end()) {
1905       check_map.insert(TimeCookieMap::value_type(
1906           it->CreationDate().ToInternalValue(), *it));
1907     }
1908   }
1909 }
1910
1911 // Mainly a test of GetEffectiveDomain, or more specifically, of the
1912 // expected behavior of GetEffectiveDomain within the CookieMonster.
1913 TEST_F(CookieMonsterTest, GetKey) {
1914   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1915
1916   // This test is really only interesting if GetKey() actually does something.
1917   EXPECT_EQ("google.com", cm->GetKey("www.google.com"));
1918   EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie"));
1919   EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie"));
1920   EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk"));
1921   EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk"));
1922   EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com"));
1923   EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie"));
1924
1925   // Cases where the effective domain is null, so we use the host
1926   // as the key.
1927   EXPECT_EQ("co.uk", cm->GetKey("co.uk"));
1928   const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1929   EXPECT_EQ(extension_name, cm->GetKey(extension_name));
1930   EXPECT_EQ("com", cm->GetKey("com"));
1931   EXPECT_EQ("hostalias", cm->GetKey("hostalias"));
1932   EXPECT_EQ("localhost", cm->GetKey("localhost"));
1933 }
1934
1935 // Test that cookies transfer from/to the backing store correctly.
1936 TEST_F(CookieMonsterTest, BackingStoreCommunication) {
1937   // Store details for cookies transforming through the backing store interface.
1938
1939   base::Time current(base::Time::Now());
1940   scoped_refptr<MockSimplePersistentCookieStore> store(
1941       new MockSimplePersistentCookieStore);
1942   base::Time new_access_time;
1943   base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1944
1945   const CookiesInputInfo input_info[] = {
1946     {GURL("http://a.b.google.com"), "a", "1", "", "/path/to/cookie", expires,
1947      false, false, COOKIE_PRIORITY_DEFAULT},
1948     {GURL("https://www.google.com"), "b", "2", ".google.com",
1949      "/path/from/cookie", expires + TimeDelta::FromSeconds(10),
1950      true, true, COOKIE_PRIORITY_DEFAULT},
1951     {GURL("https://google.com"), "c", "3", "", "/another/path/to/cookie",
1952      base::Time::Now() + base::TimeDelta::FromSeconds(100),
1953      true, false, COOKIE_PRIORITY_DEFAULT}
1954   };
1955   const int INPUT_DELETE = 1;
1956
1957   // Create new cookies and flush them to the store.
1958   {
1959     scoped_refptr<CookieMonster> cmout(new CookieMonster(store.get(), NULL));
1960     for (const CookiesInputInfo* p = input_info;
1961          p < &input_info[ARRAYSIZE_UNSAFE(input_info)];
1962          p++) {
1963       EXPECT_TRUE(SetCookieWithDetails(cmout.get(),
1964                                        p->url,
1965                                        p->name,
1966                                        p->value,
1967                                        p->domain,
1968                                        p->path,
1969                                        p->expiration_time,
1970                                        p->secure,
1971                                        p->http_only,
1972                                        p->priority));
1973     }
1974     GURL del_url(input_info[INPUT_DELETE].url.Resolve(
1975                      input_info[INPUT_DELETE].path).spec());
1976     DeleteCookie(cmout.get(), del_url, input_info[INPUT_DELETE].name);
1977   }
1978
1979   // Create a new cookie monster and make sure that everything is correct
1980   {
1981     scoped_refptr<CookieMonster> cmin(new CookieMonster(store.get(), NULL));
1982     CookieList cookies(GetAllCookies(cmin.get()));
1983     ASSERT_EQ(2u, cookies.size());
1984     // Ordering is path length, then creation time.  So second cookie
1985     // will come first, and we need to swap them.
1986     std::swap(cookies[0], cookies[1]);
1987     for (int output_index = 0; output_index < 2; output_index++) {
1988       int input_index = output_index * 2;
1989       const CookiesInputInfo* input = &input_info[input_index];
1990       const CanonicalCookie* output = &cookies[output_index];
1991
1992       EXPECT_EQ(input->name, output->Name());
1993       EXPECT_EQ(input->value, output->Value());
1994       EXPECT_EQ(input->url.host(), output->Domain());
1995       EXPECT_EQ(input->path, output->Path());
1996       EXPECT_LE(current.ToInternalValue(),
1997                 output->CreationDate().ToInternalValue());
1998       EXPECT_EQ(input->secure, output->IsSecure());
1999       EXPECT_EQ(input->http_only, output->IsHttpOnly());
2000       EXPECT_TRUE(output->IsPersistent());
2001       EXPECT_EQ(input->expiration_time.ToInternalValue(),
2002                 output->ExpiryDate().ToInternalValue());
2003     }
2004   }
2005 }
2006
2007 TEST_F(CookieMonsterTest, CookieListOrdering) {
2008   // Put a random set of cookies into a monster and make sure
2009   // they're returned in the right order.
2010   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2011   EXPECT_TRUE(
2012       SetCookie(cm.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1"));
2013   EXPECT_TRUE(SetCookie(cm.get(),
2014                         GURL("http://b.a.google.com/aa/bb/cc/x.html"),
2015                         "d=1; domain=b.a.google.com"));
2016   EXPECT_TRUE(SetCookie(cm.get(),
2017                         GURL("http://b.a.google.com/aa/bb/cc/x.html"),
2018                         "a=4; domain=b.a.google.com"));
2019   EXPECT_TRUE(SetCookie(cm.get(),
2020                         GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
2021                         "e=1; domain=c.b.a.google.com"));
2022   EXPECT_TRUE(SetCookie(
2023       cm.get(), GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1"));
2024   EXPECT_TRUE(SetCookie(
2025       cm.get(), GURL("http://news.bbc.co.uk/midpath/x.html"), "g=10"));
2026   {
2027     unsigned int i = 0;
2028     CookieList cookies(GetAllCookiesForURL(
2029         cm.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
2030     ASSERT_EQ(5u, cookies.size());
2031     EXPECT_EQ("d", cookies[i++].Name());
2032     EXPECT_EQ("a", cookies[i++].Name());
2033     EXPECT_EQ("e", cookies[i++].Name());
2034     EXPECT_EQ("b", cookies[i++].Name());
2035     EXPECT_EQ("c", cookies[i++].Name());
2036   }
2037
2038   {
2039     unsigned int i = 0;
2040     CookieList cookies(GetAllCookies(cm.get()));
2041     ASSERT_EQ(6u, cookies.size());
2042     EXPECT_EQ("d", cookies[i++].Name());
2043     EXPECT_EQ("a", cookies[i++].Name());
2044     EXPECT_EQ("e", cookies[i++].Name());
2045     EXPECT_EQ("g", cookies[i++].Name());
2046     EXPECT_EQ("b", cookies[i++].Name());
2047     EXPECT_EQ("c", cookies[i++].Name());
2048   }
2049 }
2050
2051 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
2052 // are somewhat complementary twins.  This test is probing for whether
2053 // garbage collection always happens when it should (i.e. that we actually
2054 // get rid of cookies when we should).  The perftest is probing for
2055 // whether garbage collection happens when it shouldn't.  See comments
2056 // before that test for more details.
2057
2058 // Disabled on Windows, see crbug.com/126095
2059 #if defined(OS_WIN)
2060 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers
2061 #else
2062 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers
2063 #endif
2064
2065 TEST_F(CookieMonsterTest, MAYBE_GarbageCollectionTriggers) {
2066   // First we check to make sure that a whole lot of recent cookies
2067   // doesn't get rid of anything after garbage collection is checked for.
2068   {
2069     scoped_refptr<CookieMonster> cm(
2070         CreateMonsterForGC(CookieMonster::kMaxCookies * 2));
2071     EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
2072     SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
2073     EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1,
2074               GetAllCookies(cm.get()).size());
2075   }
2076
2077   // Now we explore a series of relationships between cookie last access
2078   // time and size of store to make sure we only get rid of cookies when
2079   // we really should.
2080   const struct TestCase {
2081     size_t num_cookies;
2082     size_t num_old_cookies;
2083     size_t expected_initial_cookies;
2084     // Indexed by ExpiryAndKeyScheme
2085     size_t expected_cookies_after_set;
2086   } test_cases[] = {
2087     {
2088       // A whole lot of recent cookies; gc shouldn't happen.
2089       CookieMonster::kMaxCookies * 2,
2090       0,
2091       CookieMonster::kMaxCookies * 2,
2092       CookieMonster::kMaxCookies * 2 + 1
2093     }, {
2094       // Some old cookies, but still overflowing max.
2095       CookieMonster::kMaxCookies * 2,
2096       CookieMonster::kMaxCookies / 2,
2097       CookieMonster::kMaxCookies * 2,
2098       CookieMonster::kMaxCookies * 2 - CookieMonster::kMaxCookies / 2 + 1
2099     }, {
2100       // Old cookies enough to bring us right down to our purge line.
2101       CookieMonster::kMaxCookies * 2,
2102       CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies + 1,
2103       CookieMonster::kMaxCookies * 2,
2104       CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies
2105     }, {
2106       // Old cookies enough to bring below our purge line (which we
2107       // shouldn't do).
2108       CookieMonster::kMaxCookies * 2,
2109       CookieMonster::kMaxCookies * 3 / 2,
2110       CookieMonster::kMaxCookies * 2,
2111       CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies
2112     }
2113   };
2114
2115   for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) {
2116     const TestCase *test_case = &test_cases[ci];
2117     scoped_refptr<CookieMonster> cm(
2118         CreateMonsterFromStoreForGC(
2119             test_case->num_cookies, test_case->num_old_cookies,
2120             CookieMonster::kSafeFromGlobalPurgeDays * 2));
2121     EXPECT_EQ(test_case->expected_initial_cookies,
2122               GetAllCookies(cm.get()).size()) << "For test case " << ci;
2123     // Will trigger GC
2124     SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
2125     EXPECT_EQ(test_case->expected_cookies_after_set,
2126               GetAllCookies(cm.get()).size()) << "For test case " << ci;
2127   }
2128 }
2129
2130 // This test checks that keep expired cookies flag is working.
2131 TEST_F(CookieMonsterTest, KeepExpiredCookies) {
2132   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2133   cm->SetKeepExpiredCookies();
2134   CookieOptions options;
2135
2136   // Set a persistent cookie.
2137   ASSERT_TRUE(SetCookieWithOptions(
2138       cm.get(),
2139       url_google_,
2140       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2141       options));
2142
2143   // Get the canonical cookie.
2144   CookieList cookie_list = GetAllCookies(cm.get());
2145   ASSERT_EQ(1U, cookie_list.size());
2146
2147   // Use a past expiry date to delete the cookie.
2148   ASSERT_TRUE(SetCookieWithOptions(
2149       cm.get(),
2150       url_google_,
2151       std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2152       options));
2153
2154   // Check that the cookie with the past expiry date is still there.
2155   // GetAllCookies() also triggers garbage collection.
2156   cookie_list = GetAllCookies(cm.get());
2157   ASSERT_EQ(1U, cookie_list.size());
2158   ASSERT_TRUE(cookie_list[0].IsExpired(Time::Now()));
2159 }
2160
2161 namespace {
2162
2163 // Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2164 class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
2165  public:
2166   FlushablePersistentStore() : flush_count_(0) {}
2167
2168   virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE {
2169     std::vector<CanonicalCookie*> out_cookies;
2170     base::MessageLoop::current()->PostTask(
2171         FROM_HERE,
2172         base::Bind(&net::LoadedCallbackTask::Run,
2173                    new net::LoadedCallbackTask(loaded_callback, out_cookies)));
2174   }
2175
2176   virtual void LoadCookiesForKey(
2177       const std::string& key,
2178       const LoadedCallback& loaded_callback) OVERRIDE {
2179     Load(loaded_callback);
2180   }
2181
2182   virtual void AddCookie(const CanonicalCookie&) OVERRIDE {}
2183   virtual void UpdateCookieAccessTime(const CanonicalCookie&) OVERRIDE {}
2184   virtual void DeleteCookie(const CanonicalCookie&) OVERRIDE {}
2185   virtual void SetForceKeepSessionState() OVERRIDE {}
2186
2187   virtual void Flush(const base::Closure& callback) OVERRIDE {
2188     ++flush_count_;
2189     if (!callback.is_null())
2190       callback.Run();
2191   }
2192
2193   int flush_count() {
2194     return flush_count_;
2195   }
2196
2197  private:
2198   virtual ~FlushablePersistentStore() {}
2199
2200   volatile int flush_count_;
2201 };
2202
2203 // Counts the number of times Callback() has been run.
2204 class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> {
2205  public:
2206   CallbackCounter() : callback_count_(0) {}
2207
2208   void Callback() {
2209     ++callback_count_;
2210   }
2211
2212   int callback_count() {
2213     return callback_count_;
2214   }
2215
2216  private:
2217   friend class base::RefCountedThreadSafe<CallbackCounter>;
2218   ~CallbackCounter() {}
2219
2220   volatile int callback_count_;
2221 };
2222
2223 }  // namespace
2224
2225 // Test that FlushStore() is forwarded to the store and callbacks are posted.
2226 TEST_F(CookieMonsterTest, FlushStore) {
2227   scoped_refptr<CallbackCounter> counter(new CallbackCounter());
2228   scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
2229   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2230
2231   ASSERT_EQ(0, store->flush_count());
2232   ASSERT_EQ(0, counter->callback_count());
2233
2234   // Before initialization, FlushStore() should just run the callback.
2235   cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2236   base::MessageLoop::current()->RunUntilIdle();
2237
2238   ASSERT_EQ(0, store->flush_count());
2239   ASSERT_EQ(1, counter->callback_count());
2240
2241   // NULL callback is safe.
2242   cm->FlushStore(base::Closure());
2243   base::MessageLoop::current()->RunUntilIdle();
2244
2245   ASSERT_EQ(0, store->flush_count());
2246   ASSERT_EQ(1, counter->callback_count());
2247
2248   // After initialization, FlushStore() should delegate to the store.
2249   GetAllCookies(cm.get());  // Force init.
2250   cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2251   base::MessageLoop::current()->RunUntilIdle();
2252
2253   ASSERT_EQ(1, store->flush_count());
2254   ASSERT_EQ(2, counter->callback_count());
2255
2256   // NULL callback is still safe.
2257   cm->FlushStore(base::Closure());
2258   base::MessageLoop::current()->RunUntilIdle();
2259
2260   ASSERT_EQ(2, store->flush_count());
2261   ASSERT_EQ(2, counter->callback_count());
2262
2263   // If there's no backing store, FlushStore() is always a safe no-op.
2264   cm = new CookieMonster(NULL, NULL);
2265   GetAllCookies(cm.get());  // Force init.
2266   cm->FlushStore(base::Closure());
2267   base::MessageLoop::current()->RunUntilIdle();
2268
2269   ASSERT_EQ(2, counter->callback_count());
2270
2271   cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2272   base::MessageLoop::current()->RunUntilIdle();
2273
2274   ASSERT_EQ(3, counter->callback_count());
2275 }
2276
2277 TEST_F(CookieMonsterTest, HistogramCheck) {
2278   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2279   // Should match call in InitializeHistograms, but doesn't really matter
2280   // since the histogram should have been initialized by the CM construction
2281   // above.
2282   base::HistogramBase* expired_histogram =
2283       base::Histogram::FactoryGet(
2284           "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2285           base::Histogram::kUmaTargetedHistogramFlag);
2286
2287   scoped_ptr<base::HistogramSamples> samples1(
2288       expired_histogram->SnapshotSamples());
2289   ASSERT_TRUE(
2290       SetCookieWithDetails(cm.get(),
2291                            GURL("http://fake.a.url"),
2292                            "a",
2293                            "b",
2294                            "a.url",
2295                            "/",
2296                            base::Time::Now() + base::TimeDelta::FromMinutes(59),
2297                            false,
2298                            false,
2299                            COOKIE_PRIORITY_DEFAULT));
2300
2301   scoped_ptr<base::HistogramSamples> samples2(
2302       expired_histogram->SnapshotSamples());
2303   EXPECT_EQ(samples1->TotalCount() + 1, samples2->TotalCount());
2304
2305   // kValidCookieLine creates a session cookie.
2306   ASSERT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
2307
2308   scoped_ptr<base::HistogramSamples> samples3(
2309       expired_histogram->SnapshotSamples());
2310   EXPECT_EQ(samples2->TotalCount(), samples3->TotalCount());
2311 }
2312
2313 namespace {
2314
2315 class MultiThreadedCookieMonsterTest : public CookieMonsterTest {
2316  public:
2317   MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {}
2318
2319   // Helper methods for calling the asynchronous CookieMonster methods
2320   // from a different thread.
2321
2322   void GetAllCookiesTask(CookieMonster* cm,
2323                          GetCookieListCallback* callback) {
2324     cm->GetAllCookiesAsync(
2325         base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2326   }
2327
2328   void GetAllCookiesForURLTask(CookieMonster* cm,
2329                                const GURL& url,
2330                                GetCookieListCallback* callback) {
2331     cm->GetAllCookiesForURLAsync(
2332         url,
2333         base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2334   }
2335
2336   void GetAllCookiesForURLWithOptionsTask(CookieMonster* cm,
2337                                           const GURL& url,
2338                                           const CookieOptions& options,
2339                                           GetCookieListCallback* callback) {
2340     cm->GetAllCookiesForURLWithOptionsAsync(
2341         url, options,
2342         base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2343   }
2344
2345   void SetCookieWithDetailsTask(CookieMonster* cm, const GURL& url,
2346                                 ResultSavingCookieCallback<bool>* callback) {
2347     // Define the parameters here instead of in the calling fucntion.
2348     // The maximum number of parameters for Bind function is 6.
2349     std::string name = "A";
2350     std::string value = "B";
2351     std::string domain = std::string();
2352     std::string path = "/foo";
2353     base::Time expiration_time = base::Time();
2354     bool secure = false;
2355     bool http_only = false;
2356     CookiePriority priority = COOKIE_PRIORITY_DEFAULT;
2357     cm->SetCookieWithDetailsAsync(
2358         url, name, value, domain, path, expiration_time, secure, http_only,
2359         priority,
2360         base::Bind(
2361             &ResultSavingCookieCallback<bool>::Run,
2362             base::Unretained(callback)));
2363   }
2364
2365   void DeleteAllCreatedBetweenTask(CookieMonster* cm,
2366                                    const base::Time& delete_begin,
2367                                    const base::Time& delete_end,
2368                                    ResultSavingCookieCallback<int>* callback) {
2369     cm->DeleteAllCreatedBetweenAsync(
2370         delete_begin, delete_end,
2371         base::Bind(
2372             &ResultSavingCookieCallback<int>::Run, base::Unretained(callback)));
2373   }
2374
2375   void DeleteAllForHostTask(CookieMonster* cm,
2376                             const GURL& url,
2377                             ResultSavingCookieCallback<int>* callback) {
2378     cm->DeleteAllForHostAsync(
2379         url,
2380         base::Bind(
2381             &ResultSavingCookieCallback<int>::Run, base::Unretained(callback)));
2382   }
2383
2384   void DeleteAllCreatedBetweenForHostTask(
2385       CookieMonster* cm,
2386       const base::Time delete_begin,
2387       const base::Time delete_end,
2388       const GURL& url,
2389       ResultSavingCookieCallback<int>* callback) {
2390     cm->DeleteAllCreatedBetweenForHostAsync(
2391         delete_begin, delete_end, url,
2392         base::Bind(
2393             &ResultSavingCookieCallback<int>::Run,
2394             base::Unretained(callback)));
2395   }
2396
2397   void DeleteCanonicalCookieTask(CookieMonster* cm,
2398                                  const CanonicalCookie& cookie,
2399                                  ResultSavingCookieCallback<bool>* callback) {
2400     cm->DeleteCanonicalCookieAsync(
2401         cookie,
2402         base::Bind(
2403             &ResultSavingCookieCallback<bool>::Run,
2404             base::Unretained(callback)));
2405   }
2406
2407  protected:
2408   void RunOnOtherThread(const base::Closure& task) {
2409     other_thread_.Start();
2410     other_thread_.message_loop()->PostTask(FROM_HERE, task);
2411     RunFor(kTimeout);
2412     other_thread_.Stop();
2413   }
2414
2415   Thread other_thread_;
2416 };
2417
2418 }  // namespace
2419
2420 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookies) {
2421   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2422   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2423   CookieList cookies = GetAllCookies(cm.get());
2424   CookieList::const_iterator it = cookies.begin();
2425   ASSERT_TRUE(it != cookies.end());
2426   EXPECT_EQ("www.google.izzle", it->Domain());
2427   EXPECT_EQ("A", it->Name());
2428   ASSERT_TRUE(++it == cookies.end());
2429   GetCookieListCallback callback(&other_thread_);
2430   base::Closure task =
2431       base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesTask,
2432                  base::Unretained(this),
2433                  cm, &callback);
2434   RunOnOtherThread(task);
2435   EXPECT_TRUE(callback.did_run());
2436   it = callback.cookies().begin();
2437   ASSERT_TRUE(it != callback.cookies().end());
2438   EXPECT_EQ("www.google.izzle", it->Domain());
2439   EXPECT_EQ("A", it->Name());
2440   ASSERT_TRUE(++it == callback.cookies().end());
2441 }
2442
2443 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURL) {
2444   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2445   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2446   CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
2447   CookieList::const_iterator it = cookies.begin();
2448   ASSERT_TRUE(it != cookies.end());
2449   EXPECT_EQ("www.google.izzle", it->Domain());
2450   EXPECT_EQ("A", it->Name());
2451   ASSERT_TRUE(++it == cookies.end());
2452   GetCookieListCallback callback(&other_thread_);
2453   base::Closure task =
2454       base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask,
2455                  base::Unretained(this),
2456                  cm, url_google_, &callback);
2457   RunOnOtherThread(task);
2458   EXPECT_TRUE(callback.did_run());
2459   it = callback.cookies().begin();
2460   ASSERT_TRUE(it != callback.cookies().end());
2461   EXPECT_EQ("www.google.izzle", it->Domain());
2462   EXPECT_EQ("A", it->Name());
2463   ASSERT_TRUE(++it == callback.cookies().end());
2464 }
2465
2466 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURLWithOpt) {
2467   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2468   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2469   CookieOptions options;
2470   CookieList cookies =
2471       GetAllCookiesForURLWithOptions(cm.get(), url_google_, options);
2472   CookieList::const_iterator it = cookies.begin();
2473   ASSERT_TRUE(it != cookies.end());
2474   EXPECT_EQ("www.google.izzle", it->Domain());
2475   EXPECT_EQ("A", it->Name());
2476   ASSERT_TRUE(++it == cookies.end());
2477   GetCookieListCallback callback(&other_thread_);
2478   base::Closure task = base::Bind(
2479       &net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask,
2480       base::Unretained(this),
2481       cm, url_google_, options, &callback);
2482   RunOnOtherThread(task);
2483   EXPECT_TRUE(callback.did_run());
2484   it = callback.cookies().begin();
2485   ASSERT_TRUE(it != callback.cookies().end());
2486   EXPECT_EQ("www.google.izzle", it->Domain());
2487   EXPECT_EQ("A", it->Name());
2488   ASSERT_TRUE(++it == callback.cookies().end());
2489 }
2490
2491 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) {
2492   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2493   EXPECT_TRUE(SetCookieWithDetails(cm.get(),
2494                                    url_google_foo_,
2495                                    "A",
2496                                    "B",
2497                                    std::string(),
2498                                    "/foo",
2499                                    base::Time(),
2500                                    false,
2501                                    false,
2502                                    COOKIE_PRIORITY_DEFAULT));
2503   ResultSavingCookieCallback<bool> callback(&other_thread_);
2504   base::Closure task = base::Bind(
2505       &net::MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask,
2506       base::Unretained(this),
2507       cm, url_google_foo_, &callback);
2508   RunOnOtherThread(task);
2509   EXPECT_TRUE(callback.did_run());
2510   EXPECT_TRUE(callback.result());
2511 }
2512
2513 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllCreatedBetween) {
2514   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2515   CookieOptions options;
2516   Time now = Time::Now();
2517   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2518   EXPECT_EQ(
2519       1,
2520       DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99), Time()));
2521   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2522   ResultSavingCookieCallback<int> callback(&other_thread_);
2523   base::Closure task = base::Bind(
2524       &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask,
2525       base::Unretained(this),
2526       cm, now - TimeDelta::FromDays(99),
2527       Time(), &callback);
2528   RunOnOtherThread(task);
2529   EXPECT_TRUE(callback.did_run());
2530   EXPECT_EQ(1, callback.result());
2531 }
2532
2533 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllForHost) {
2534   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2535   CookieOptions options;
2536   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2537   EXPECT_EQ(1, DeleteAllForHost(cm.get(), url_google_));
2538   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2539   ResultSavingCookieCallback<int> callback(&other_thread_);
2540   base::Closure task = base::Bind(
2541       &net::MultiThreadedCookieMonsterTest::DeleteAllForHostTask,
2542       base::Unretained(this),
2543       cm, url_google_, &callback);
2544   RunOnOtherThread(task);
2545   EXPECT_TRUE(callback.did_run());
2546   EXPECT_EQ(1, callback.result());
2547 }
2548
2549 TEST_F(MultiThreadedCookieMonsterTest,
2550        ThreadCheckDeleteAllCreatedBetweenForHost) {
2551   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2552   GURL url_not_google("http://www.notgoogle.com");
2553
2554   CookieOptions options;
2555   Time now = Time::Now();
2556   // ago1 < ago2 < ago3 < now.
2557   Time ago1 = now - TimeDelta::FromDays(101);
2558   Time ago2 = now - TimeDelta::FromDays(100);
2559   Time ago3 = now - TimeDelta::FromDays(99);
2560
2561   // These 3 cookies match the first deletion.
2562   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2563   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "C=D", options));
2564   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "Y=Z", options));
2565
2566   // This cookie does not match host.
2567   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_not_google, "E=F", options));
2568
2569   // This cookie does not match time range: [ago3, inf], for first deletion, but
2570   // matches for the second deletion.
2571   EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "G=H", ago2));
2572
2573   // 1. First set of deletions.
2574   EXPECT_EQ(
2575       3,  // Deletes A=B, C=D, Y=Z
2576       DeleteAllCreatedBetweenForHost(
2577           cm.get(), ago3, Time::Max(), url_google_));
2578
2579   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2580   ResultSavingCookieCallback<int> callback(&other_thread_);
2581
2582   // 2. Second set of deletions.
2583   base::Closure task = base::Bind(
2584       &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask,
2585       base::Unretained(this),
2586       cm, ago1, Time(), url_google_,
2587       &callback);
2588   RunOnOtherThread(task);
2589   EXPECT_TRUE(callback.did_run());
2590   EXPECT_EQ(2, callback.result());  // Deletes A=B, G=H.
2591 }
2592
2593 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) {
2594   scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2595   CookieOptions options;
2596   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2597   CookieList cookies = GetAllCookies(cm.get());
2598   CookieList::iterator it = cookies.begin();
2599   EXPECT_TRUE(DeleteCanonicalCookie(cm.get(), *it));
2600
2601   EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2602   ResultSavingCookieCallback<bool> callback(&other_thread_);
2603   cookies = GetAllCookies(cm.get());
2604   it = cookies.begin();
2605   base::Closure task = base::Bind(
2606       &net::MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask,
2607       base::Unretained(this),
2608       cm, *it, &callback);
2609   RunOnOtherThread(task);
2610   EXPECT_TRUE(callback.did_run());
2611   EXPECT_TRUE(callback.result());
2612 }
2613
2614 TEST_F(CookieMonsterTest, InvalidExpiryTime) {
2615   std::string cookie_line =
2616       std::string(kValidCookieLine) + "; expires=Blarg arg arg";
2617   scoped_ptr<CanonicalCookie> cookie(
2618       CanonicalCookie::Create(url_google_, cookie_line, Time::Now(),
2619                               CookieOptions()));
2620   ASSERT_FALSE(cookie->IsPersistent());
2621 }
2622
2623 // Test that CookieMonster writes session cookies into the underlying
2624 // CookieStore if the "persist session cookies" option is on.
2625 TEST_F(CookieMonsterTest, PersistSessionCookies) {
2626   scoped_refptr<MockPersistentCookieStore> store(
2627       new MockPersistentCookieStore);
2628   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2629   cm->SetPersistSessionCookies(true);
2630
2631   // All cookies set with SetCookie are session cookies.
2632   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2633   EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
2634
2635   // The cookie was written to the backing store.
2636   EXPECT_EQ(1u, store->commands().size());
2637   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
2638   EXPECT_EQ("A", store->commands()[0].cookie.Name());
2639   EXPECT_EQ("B", store->commands()[0].cookie.Value());
2640
2641   // Modify the cookie.
2642   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=C"));
2643   EXPECT_EQ("A=C", GetCookies(cm.get(), url_google_));
2644   EXPECT_EQ(3u, store->commands().size());
2645   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2646   EXPECT_EQ("A", store->commands()[1].cookie.Name());
2647   EXPECT_EQ("B", store->commands()[1].cookie.Value());
2648   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
2649   EXPECT_EQ("A", store->commands()[2].cookie.Name());
2650   EXPECT_EQ("C", store->commands()[2].cookie.Value());
2651
2652   // Delete the cookie.
2653   DeleteCookie(cm.get(), url_google_, "A");
2654   EXPECT_EQ("", GetCookies(cm.get(), url_google_));
2655   EXPECT_EQ(4u, store->commands().size());
2656   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
2657   EXPECT_EQ("A", store->commands()[3].cookie.Name());
2658   EXPECT_EQ("C", store->commands()[3].cookie.Value());
2659 }
2660
2661 // Test the commands sent to the persistent cookie store.
2662 TEST_F(CookieMonsterTest, PersisentCookieStorageTest) {
2663   scoped_refptr<MockPersistentCookieStore> store(
2664       new MockPersistentCookieStore);
2665   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2666
2667   // Add a cookie.
2668   EXPECT_TRUE(SetCookie(
2669       cm.get(), url_google_, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2670   this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
2671   ASSERT_EQ(1u, store->commands().size());
2672   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
2673   // Remove it.
2674   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B; max-age=0"));
2675   this->MatchCookieLines(std::string(), GetCookies(cm.get(), url_google_));
2676   ASSERT_EQ(2u, store->commands().size());
2677   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2678
2679   // Add a cookie.
2680   EXPECT_TRUE(SetCookie(
2681       cm.get(), url_google_, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2682   this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
2683   ASSERT_EQ(3u, store->commands().size());
2684   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
2685   // Overwrite it.
2686   EXPECT_TRUE(SetCookie(
2687       cm.get(), url_google_, "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
2688   this->MatchCookieLines("A=Foo", GetCookies(cm.get(), url_google_));
2689   ASSERT_EQ(5u, store->commands().size());
2690   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
2691   EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type);
2692
2693   // Create some non-persistent cookies and check that they don't go to the
2694   // persistent storage.
2695   EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=Bar"));
2696   this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm.get(), url_google_));
2697   EXPECT_EQ(5u, store->commands().size());
2698 }
2699
2700 // Test to assure that cookies with control characters are purged appropriately.
2701 // See http://crbug.com/238041 for background.
2702 TEST_F(CookieMonsterTest, ControlCharacterPurge) {
2703   const Time now1(Time::Now());
2704   const Time now2(Time::Now() + TimeDelta::FromSeconds(1));
2705   const Time now3(Time::Now() + TimeDelta::FromSeconds(2));
2706   const Time later(now1 + TimeDelta::FromDays(1));
2707   const GURL url("http://host/path");
2708   const std::string domain("host");
2709   const std::string path("/path");
2710
2711   scoped_refptr<MockPersistentCookieStore> store(
2712       new MockPersistentCookieStore);
2713
2714   std::vector<CanonicalCookie*> initial_cookies;
2715
2716   AddCookieToList(domain,
2717                   "foo=bar; path=" + path,
2718                   now1,
2719                   &initial_cookies);
2720
2721   // We have to manually build this cookie because it contains a control
2722   // character, and our cookie line parser rejects control characters.
2723   CanonicalCookie *cc = new CanonicalCookie(url, "baz", "\x05" "boo", domain,
2724                                             path, now2, later, now2, false,
2725                                             false, COOKIE_PRIORITY_DEFAULT);
2726   initial_cookies.push_back(cc);
2727
2728   AddCookieToList(domain,
2729                   "hello=world; path=" + path,
2730                   now3,
2731                   &initial_cookies);
2732
2733   // Inject our initial cookies into the mock PersistentCookieStore.
2734   store->SetLoadExpectation(true, initial_cookies);
2735
2736   scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2737
2738   EXPECT_EQ("foo=bar; hello=world", GetCookies(cm.get(), url));
2739 }
2740
2741 }  // namespace net