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