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