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