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