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.
5 #include "net/cookies/cookie_store_unittest.h"
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/memory/scoped_vector.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/histogram.h"
18 #include "base/metrics/histogram_samples.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_piece.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_tokenizer.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/threading/thread.h"
25 #include "base/time/time.h"
26 #include "net/cookies/canonical_cookie.h"
27 #include "net/cookies/cookie_constants.h"
28 #include "net/cookies/cookie_monster.h"
29 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
30 #include "net/cookies/cookie_util.h"
31 #include "net/cookies/parsed_cookie.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
39 using base::TimeDelta
;
43 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and
44 // brethren) with this one, and remove the 'New' prefix.
45 class NewMockPersistentCookieStore
46 : public CookieMonster::PersistentCookieStore
{
48 MOCK_METHOD1(Load
, void(const LoadedCallback
& loaded_callback
));
49 MOCK_METHOD2(LoadCookiesForKey
, void(const std::string
& key
,
50 const LoadedCallback
& loaded_callback
));
51 MOCK_METHOD1(AddCookie
, void(const CanonicalCookie
& cc
));
52 MOCK_METHOD1(UpdateCookieAccessTime
, void(const CanonicalCookie
& cc
));
53 MOCK_METHOD1(DeleteCookie
, void(const CanonicalCookie
& cc
));
54 virtual void Flush(const base::Closure
& callback
) {
55 if (!callback
.is_null())
56 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
58 MOCK_METHOD0(SetForceKeepSessionState
, void());
61 virtual ~NewMockPersistentCookieStore() {}
64 const char* kTopLevelDomainPlus1
= "http://www.harvard.edu";
65 const char* kTopLevelDomainPlus2
= "http://www.math.harvard.edu";
66 const char* kTopLevelDomainPlus2Secure
= "https://www.math.harvard.edu";
67 const char* kTopLevelDomainPlus3
=
68 "http://www.bourbaki.math.harvard.edu";
69 const char* kOtherDomain
= "http://www.mit.edu";
70 const char kUrlGoogleSpecific
[] = "http://www.gmail.google.izzle";
72 class GetCookieListCallback
: public CookieCallback
{
74 GetCookieListCallback() {}
75 explicit GetCookieListCallback(Thread
* run_in_thread
)
76 : CookieCallback(run_in_thread
) {}
78 void Run(const CookieList
& cookies
) {
83 const CookieList
& cookies() { return cookies_
; }
89 struct CookieMonsterTestTraits
{
90 static scoped_refptr
<CookieStore
> Create() {
91 return new CookieMonster(NULL
, NULL
);
94 static const bool is_cookie_monster
= true;
95 static const bool supports_http_only
= true;
96 static const bool supports_non_dotted_domains
= true;
97 static const bool supports_trailing_dots
= true;
98 static const bool filters_schemes
= true;
99 static const bool has_path_prefix_bug
= false;
100 static const int creation_time_granularity_in_ms
= 0;
103 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
105 CookieMonsterTestTraits
);
107 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
108 MultiThreadedCookieStoreTest
,
109 CookieMonsterTestTraits
);
111 class CookieMonsterTest
: public CookieStoreTest
<CookieMonsterTestTraits
> {
114 CookieList
GetAllCookies(CookieMonster
* cm
) {
116 GetCookieListCallback callback
;
117 cm
->GetAllCookiesAsync(
118 base::Bind(&GetCookieListCallback::Run
,
119 base::Unretained(&callback
)));
121 EXPECT_TRUE(callback
.did_run());
122 return callback
.cookies();
125 CookieList
GetAllCookiesForURL(CookieMonster
* cm
,
128 GetCookieListCallback callback
;
129 cm
->GetAllCookiesForURLAsync(
130 url
, base::Bind(&GetCookieListCallback::Run
,
131 base::Unretained(&callback
)));
133 EXPECT_TRUE(callback
.did_run());
134 return callback
.cookies();
137 CookieList
GetAllCookiesForURLWithOptions(CookieMonster
* cm
,
139 const CookieOptions
& options
) {
141 GetCookieListCallback callback
;
142 cm
->GetAllCookiesForURLWithOptionsAsync(
143 url
, options
, base::Bind(&GetCookieListCallback::Run
,
144 base::Unretained(&callback
)));
146 EXPECT_TRUE(callback
.did_run());
147 return callback
.cookies();
150 bool SetCookieWithDetails(CookieMonster
* cm
,
152 const std::string
& name
,
153 const std::string
& value
,
154 const std::string
& domain
,
155 const std::string
& path
,
156 const base::Time
& expiration_time
,
159 CookiePriority priority
) {
161 ResultSavingCookieCallback
<bool> callback
;
162 cm
->SetCookieWithDetailsAsync(
163 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
166 &ResultSavingCookieCallback
<bool>::Run
,
167 base::Unretained(&callback
)));
169 EXPECT_TRUE(callback
.did_run());
170 return callback
.result();
173 int DeleteAll(CookieMonster
*cm
) {
175 ResultSavingCookieCallback
<int> callback
;
178 &ResultSavingCookieCallback
<int>::Run
,
179 base::Unretained(&callback
)));
181 EXPECT_TRUE(callback
.did_run());
182 return callback
.result();
185 int DeleteAllCreatedBetween(CookieMonster
*cm
,
186 const base::Time
& delete_begin
,
187 const base::Time
& delete_end
) {
189 ResultSavingCookieCallback
<int> callback
;
190 cm
->DeleteAllCreatedBetweenAsync(
191 delete_begin
, delete_end
,
193 &ResultSavingCookieCallback
<int>::Run
,
194 base::Unretained(&callback
)));
196 EXPECT_TRUE(callback
.did_run());
197 return callback
.result();
200 int DeleteAllCreatedBetweenForHost(CookieMonster
* cm
,
201 const base::Time delete_begin
,
202 const base::Time delete_end
,
205 ResultSavingCookieCallback
<int> callback
;
206 cm
->DeleteAllCreatedBetweenForHostAsync(
207 delete_begin
, delete_end
, url
,
209 &ResultSavingCookieCallback
<int>::Run
,
210 base::Unretained(&callback
)));
212 EXPECT_TRUE(callback
.did_run());
213 return callback
.result();
216 int DeleteAllForHost(CookieMonster
* cm
,
219 ResultSavingCookieCallback
<int> callback
;
220 cm
->DeleteAllForHostAsync(
221 url
, base::Bind(&ResultSavingCookieCallback
<int>::Run
,
222 base::Unretained(&callback
)));
224 EXPECT_TRUE(callback
.did_run());
225 return callback
.result();
228 bool DeleteCanonicalCookie(CookieMonster
* cm
, const CanonicalCookie
& cookie
) {
230 ResultSavingCookieCallback
<bool> callback
;
231 cm
->DeleteCanonicalCookieAsync(
233 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
234 base::Unretained(&callback
)));
236 EXPECT_TRUE(callback
.did_run());
237 return callback
.result();
240 // Helper for DeleteAllForHost test; repopulates CM with same layout
242 void PopulateCmForDeleteAllForHost(scoped_refptr
<CookieMonster
> cm
) {
243 GURL
url_top_level_domain_plus_1(kTopLevelDomainPlus1
);
244 GURL
url_top_level_domain_plus_2(kTopLevelDomainPlus2
);
245 GURL
url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure
);
246 GURL
url_top_level_domain_plus_3(kTopLevelDomainPlus3
);
247 GURL
url_other(kOtherDomain
);
251 // Static population for probe:
252 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
253 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
254 // * http_only cookie (w.c.b.a)
255 // * Two secure cookies (.c.b.a, w.c.b.a)
256 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
257 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
260 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
261 url_top_level_domain_plus_1
,
269 COOKIE_PRIORITY_DEFAULT
));
270 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
271 url_top_level_domain_plus_2
,
279 COOKIE_PRIORITY_DEFAULT
));
280 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
281 url_top_level_domain_plus_3
,
284 ".bourbaki.math.harvard.edu",
289 COOKIE_PRIORITY_DEFAULT
));
292 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
293 url_top_level_domain_plus_1
,
301 COOKIE_PRIORITY_DEFAULT
));
302 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
303 url_top_level_domain_plus_2
,
311 COOKIE_PRIORITY_DEFAULT
));
312 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
313 url_top_level_domain_plus_3
,
321 COOKIE_PRIORITY_DEFAULT
));
324 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
325 url_top_level_domain_plus_2
,
333 COOKIE_PRIORITY_DEFAULT
));
336 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
337 url_top_level_domain_plus_2_secure
,
345 COOKIE_PRIORITY_DEFAULT
));
346 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
347 url_top_level_domain_plus_2_secure
,
355 COOKIE_PRIORITY_DEFAULT
));
357 // Domain path cookies
358 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
359 url_top_level_domain_plus_2
,
367 COOKIE_PRIORITY_DEFAULT
));
368 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
369 url_top_level_domain_plus_2
,
377 COOKIE_PRIORITY_DEFAULT
));
380 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
381 url_top_level_domain_plus_2
,
389 COOKIE_PRIORITY_DEFAULT
));
390 EXPECT_TRUE(this->SetCookieWithDetails(cm
.get(),
391 url_top_level_domain_plus_2
,
399 COOKIE_PRIORITY_DEFAULT
));
401 EXPECT_EQ(13U, this->GetAllCookies(cm
.get()).size());
404 Time
GetFirstCookieAccessDate(CookieMonster
* cm
) {
405 const CookieList
all_cookies(this->GetAllCookies(cm
));
406 return all_cookies
.front().LastAccessDate();
409 bool FindAndDeleteCookie(CookieMonster
* cm
,
410 const std::string
& domain
,
411 const std::string
& name
) {
412 CookieList cookies
= this->GetAllCookies(cm
);
413 for (CookieList::iterator it
= cookies
.begin();
414 it
!= cookies
.end(); ++it
)
415 if (it
->Domain() == domain
&& it
->Name() == name
)
416 return this->DeleteCanonicalCookie(cm
, *it
);
420 int CountInString(const std::string
& str
, char c
) {
421 return std::count(str
.begin(), str
.end(), c
);
424 void TestHostGarbageCollectHelper() {
425 int domain_max_cookies
= CookieMonster::kDomainMaxCookies
;
426 int domain_purge_cookies
= CookieMonster::kDomainPurgeCookies
;
427 const int more_than_enough_cookies
=
428 (domain_max_cookies
+ domain_purge_cookies
) * 2;
429 // Add a bunch of cookies on a single host, should purge them.
431 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
432 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
433 std::string cookie
= base::StringPrintf("a%03d=b", i
);
434 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie
));
435 std::string cookies
= this->GetCookies(cm
.get(), url_google_
);
436 // Make sure we find it in the cookies.
437 EXPECT_NE(cookies
.find(cookie
), std::string::npos
);
438 // Count the number of cookies.
439 EXPECT_LE(CountInString(cookies
, '='), domain_max_cookies
);
443 // Add a bunch of cookies on multiple hosts within a single eTLD.
444 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
445 // between them. We shouldn't go above kDomainMaxCookies for both together.
446 GURL
url_google_specific(kUrlGoogleSpecific
);
448 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
449 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
450 std::string cookie_general
= base::StringPrintf("a%03d=b", i
);
451 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie_general
));
452 std::string cookie_specific
= base::StringPrintf("c%03d=b", i
);
453 EXPECT_TRUE(SetCookie(cm
.get(), url_google_specific
, cookie_specific
));
454 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
455 EXPECT_NE(cookies_general
.find(cookie_general
), std::string::npos
);
456 std::string cookies_specific
=
457 this->GetCookies(cm
.get(), url_google_specific
);
458 EXPECT_NE(cookies_specific
.find(cookie_specific
), std::string::npos
);
459 EXPECT_LE((CountInString(cookies_general
, '=') +
460 CountInString(cookies_specific
, '=')),
463 // After all this, there should be at least
464 // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
465 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
466 std::string cookies_specific
=
467 this->GetCookies(cm
.get(), url_google_specific
);
468 int total_cookies
= (CountInString(cookies_general
, '=') +
469 CountInString(cookies_specific
, '='));
470 EXPECT_GE(total_cookies
, domain_max_cookies
- domain_purge_cookies
);
471 EXPECT_LE(total_cookies
, domain_max_cookies
);
475 CookiePriority
CharToPriority(char ch
) {
478 return COOKIE_PRIORITY_LOW
;
480 return COOKIE_PRIORITY_MEDIUM
;
482 return COOKIE_PRIORITY_HIGH
;
485 return COOKIE_PRIORITY_DEFAULT
;
488 // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
489 // priorities specified by |coded_priority_str|, and tests priority-aware
490 // domain cookie eviction.
491 // |coded_priority_str| specifies a run-length-encoded string of priorities.
492 // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
493 // from least- to most-recently accessed) insertion of 2 medium-priority
494 // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4
495 // high-priority cookies.
496 // Within each priority, only the least-accessed cookies should be evicted.
497 // Thus, to describe expected suriving cookies, it suffices to specify the
498 // expected population of surviving cookies per priority, i.e.,
499 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
500 void TestPriorityCookieCase(CookieMonster
* cm
,
501 const std::string
& coded_priority_str
,
502 size_t expected_low_count
,
503 size_t expected_medium_count
,
504 size_t expected_high_count
) {
506 int next_cookie_id
= 0;
507 std::vector
<CookiePriority
> priority_list
;
508 std::vector
<int> id_list
[3]; // Indexed by CookiePriority.
510 // Parse |coded_priority_str| and add cookies.
511 std::vector
<std::string
> priority_tok_list
;
512 base::SplitString(coded_priority_str
, ' ', &priority_tok_list
);
513 for (std::vector
<std::string
>::iterator it
= priority_tok_list
.begin();
514 it
!= priority_tok_list
.end(); ++it
) {
515 size_t len
= it
->length();
517 // Take last character as priority.
518 CookiePriority priority
= CharToPriority((*it
)[len
- 1]);
519 std::string priority_str
= CookiePriorityToString(priority
);
520 // The rest of the string (possibly empty) specifies repetition.
523 bool result
= base::StringToInt(
524 base::StringPiece(it
->begin(), it
->end() - 1), &rep
);
527 for (; rep
> 0; --rep
, ++next_cookie_id
) {
528 std::string cookie
= base::StringPrintf(
529 "a%d=b;priority=%s", next_cookie_id
, priority_str
.c_str());
530 EXPECT_TRUE(SetCookie(cm
, url_google_
, cookie
));
531 priority_list
.push_back(priority
);
532 id_list
[priority
].push_back(next_cookie_id
);
536 int num_cookies
= static_cast<int>(priority_list
.size());
537 std::vector
<int> surviving_id_list
[3]; // Indexed by CookiePriority.
539 // Parse the list of cookies
540 std::string cookie_str
= this->GetCookies(cm
, url_google_
);
541 std::vector
<std::string
> cookie_tok_list
;
542 base::SplitString(cookie_str
, ';', &cookie_tok_list
);
543 for (std::vector
<std::string
>::iterator it
= cookie_tok_list
.begin();
544 it
!= cookie_tok_list
.end(); ++it
) {
545 // Assuming *it is "a#=b", so extract and parse "#" portion.
547 bool result
= base::StringToInt(
548 base::StringPiece(it
->begin() + 1, it
->end() - 2), &id
);
551 DCHECK_LT(id
, num_cookies
);
552 surviving_id_list
[priority_list
[id
]].push_back(id
);
555 // Validate each priority.
556 size_t expected_count
[3] = {
557 expected_low_count
, expected_medium_count
, expected_high_count
559 for (int i
= 0; i
< 3; ++i
) {
560 DCHECK_LE(surviving_id_list
[i
].size(), id_list
[i
].size());
561 EXPECT_EQ(expected_count
[i
], surviving_id_list
[i
].size());
562 // Verify that the remaining cookies are the most recent among those
563 // with the same priorities.
564 if (expected_count
[i
] == surviving_id_list
[i
].size()) {
565 std::sort(surviving_id_list
[i
].begin(), surviving_id_list
[i
].end());
566 EXPECT_TRUE(std::equal(surviving_id_list
[i
].begin(),
567 surviving_id_list
[i
].end(),
568 id_list
[i
].end() - expected_count
[i
]));
573 void TestPriorityAwareGarbageCollectHelper() {
574 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
575 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies
);
576 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies
-
577 CookieMonster::kDomainPurgeCookies
);
578 DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow
);
579 DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium
);
580 DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh
);
582 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
584 // Each test case adds 181 cookies, so 31 cookies are evicted.
585 // Cookie same priority, repeated for each priority.
586 TestPriorityCookieCase(cm
.get(), "181L", 150U, 0U, 0U);
587 TestPriorityCookieCase(cm
.get(), "181M", 0U, 150U, 0U);
588 TestPriorityCookieCase(cm
.get(), "181H", 0U, 0U, 150U);
590 // Pairwise scenarios.
591 // Round 1 => none; round2 => 31M; round 3 => none.
592 TestPriorityCookieCase(cm
.get(), "10H 171M", 0U, 140U, 10U);
593 // Round 1 => 10L; round2 => 21M; round 3 => none.
594 TestPriorityCookieCase(cm
.get(), "141M 40L", 30U, 120U, 0U);
595 // Round 1 => none; round2 => none; round 3 => 31H.
596 TestPriorityCookieCase(cm
.get(), "101H 80M", 0U, 80U, 70U);
598 // For {low, medium} priorities right on quota, different orders.
599 // Round 1 => 1L; round 2 => none, round3 => 30L.
600 TestPriorityCookieCase(cm
.get(), "31L 50M 100H", 0U, 50U, 100U);
601 // Round 1 => none; round 2 => 1M, round3 => 30M.
602 TestPriorityCookieCase(cm
.get(), "51M 100H 30L", 30U, 20U, 100U);
603 // Round 1 => none; round 2 => none; round3 => 31H.
604 TestPriorityCookieCase(cm
.get(), "101H 50M 30L", 30U, 50U, 70U);
606 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
607 TestPriorityCookieCase(cm
.get(), "81H 60M 40L", 30U, 50U, 70U);
609 // More complex scenarios.
610 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
611 TestPriorityCookieCase(cm
.get(), "21H 60M 40L 60H", 30U, 50U, 70U);
612 // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
613 TestPriorityCookieCase(
614 cm
.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U, 21U);
615 // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
616 TestPriorityCookieCase(cm
.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U);
617 // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
618 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U);
619 // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
620 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U);
623 // Function for creating a CM with a number of cookies in it,
624 // no store (and hence no ability to affect access time).
625 CookieMonster
* CreateMonsterForGC(int num_cookies
) {
626 CookieMonster
* cm(new CookieMonster(NULL
, NULL
));
627 for (int i
= 0; i
< num_cookies
; i
++) {
628 SetCookie(cm
, GURL(base::StringPrintf("http://h%05d.izzle", i
)), "a=1");
634 // TODO(erikwright): Replace the other callbacks and synchronous helper methods
635 // in this test suite with these Mocks.
636 template<typename T
, typename C
> class MockCookieCallback
{
639 return base::Bind(&T::Invoke
, base::Unretained(static_cast<T
*>(this)));
643 class MockGetCookiesCallback
644 : public MockCookieCallback
<MockGetCookiesCallback
,
645 CookieStore::GetCookiesCallback
> {
647 MOCK_METHOD1(Invoke
, void(const std::string
& cookies
));
650 class MockSetCookiesCallback
651 : public MockCookieCallback
<MockSetCookiesCallback
,
652 CookieStore::SetCookiesCallback
> {
654 MOCK_METHOD1(Invoke
, void(bool success
));
658 : public MockCookieCallback
<MockClosure
, base::Closure
> {
660 MOCK_METHOD0(Invoke
, void(void));
663 class MockGetCookieListCallback
664 : public MockCookieCallback
<MockGetCookieListCallback
,
665 CookieMonster::GetCookieListCallback
> {
667 MOCK_METHOD1(Invoke
, void(const CookieList
& cookies
));
670 class MockDeleteCallback
671 : public MockCookieCallback
<MockDeleteCallback
,
672 CookieMonster::DeleteCallback
> {
674 MOCK_METHOD1(Invoke
, void(int num_deleted
));
677 class MockDeleteCookieCallback
678 : public MockCookieCallback
<MockDeleteCookieCallback
,
679 CookieMonster::DeleteCookieCallback
> {
681 MOCK_METHOD1(Invoke
, void(bool success
));
684 struct CookiesInputInfo
{
686 const std::string name
;
687 const std::string value
;
688 const std::string domain
;
689 const std::string path
;
690 const base::Time expiration_time
;
693 CookiePriority priority
;
696 ACTION(QuitCurrentMessageLoop
) {
697 base::MessageLoop::current()->PostTask(FROM_HERE
,
698 base::MessageLoop::QuitClosure());
701 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
702 // rename these, removing the 'Action' suffix.
703 ACTION_P4(DeleteCookieAction
, cookie_monster
, url
, name
, callback
) {
704 cookie_monster
->DeleteCookieAsync(url
, name
, callback
->AsCallback());
706 ACTION_P3(GetCookiesAction
, cookie_monster
, url
, callback
) {
707 cookie_monster
->GetCookiesWithOptionsAsync(
708 url
, CookieOptions(), callback
->AsCallback());
710 ACTION_P4(SetCookieAction
, cookie_monster
, url
, cookie_line
, callback
) {
711 cookie_monster
->SetCookieWithOptionsAsync(
712 url
, cookie_line
, CookieOptions(), callback
->AsCallback());
714 ACTION_P4(DeleteAllCreatedBetweenAction
,
715 cookie_monster
, delete_begin
, delete_end
, callback
) {
716 cookie_monster
->DeleteAllCreatedBetweenAsync(
717 delete_begin
, delete_end
, callback
->AsCallback());
719 ACTION_P3(SetCookieWithDetailsAction
, cookie_monster
, cc
, callback
) {
720 cookie_monster
->SetCookieWithDetailsAsync(
721 cc
.url
, cc
.name
, cc
.value
, cc
.domain
, cc
.path
, cc
.expiration_time
,
722 cc
.secure
, cc
.http_only
, cc
.priority
,
723 callback
->AsCallback());
726 ACTION_P2(GetAllCookiesAction
, cookie_monster
, callback
) {
727 cookie_monster
->GetAllCookiesAsync(callback
->AsCallback());
730 ACTION_P3(DeleteAllForHostAction
, cookie_monster
, url
, callback
) {
731 cookie_monster
->DeleteAllForHostAsync(url
, callback
->AsCallback());
734 ACTION_P3(DeleteCanonicalCookieAction
, cookie_monster
, cookie
, callback
) {
735 cookie_monster
->DeleteCanonicalCookieAsync(cookie
, callback
->AsCallback());
738 ACTION_P2(DeleteAllAction
, cookie_monster
, callback
) {
739 cookie_monster
->DeleteAllAsync(callback
->AsCallback());
742 ACTION_P3(GetAllCookiesForUrlWithOptionsAction
, cookie_monster
, url
, callback
) {
743 cookie_monster
->GetAllCookiesForURLWithOptionsAsync(
744 url
, CookieOptions(), callback
->AsCallback());
747 ACTION_P3(GetAllCookiesForUrlAction
, cookie_monster
, url
, callback
) {
748 cookie_monster
->GetAllCookiesForURLAsync(url
, callback
->AsCallback());
751 ACTION_P(PushCallbackAction
, callback_vector
) {
752 callback_vector
->push(arg1
);
755 ACTION_P2(DeleteSessionCookiesAction
, cookie_monster
, callback
) {
756 cookie_monster
->DeleteSessionCookiesAsync(callback
->AsCallback());
761 // This test suite verifies the task deferral behaviour of the CookieMonster.
762 // Specifically, for each asynchronous method, verify that:
763 // 1. invoking it on an uninitialized cookie store causes the store to begin
764 // chain-loading its backing data or loading data for a specific domain key
766 // 2. The initial invocation does not complete until the loading completes.
767 // 3. Invocations after the loading has completed complete immediately.
768 class DeferredCookieTaskTest
: public CookieMonsterTest
{
770 DeferredCookieTaskTest() {
771 persistent_store_
= new NewMockPersistentCookieStore();
772 cookie_monster_
= new CookieMonster(persistent_store_
.get(), NULL
);
775 // Defines a cookie to be returned from PersistentCookieStore::Load
776 void DeclareLoadedCookie(const std::string
& key
,
777 const std::string
& cookie_line
,
778 const base::Time
& creation_time
) {
779 AddCookieToList(key
, cookie_line
, creation_time
, &loaded_cookies_
);
782 // Runs the message loop, waiting until PersistentCookieStore::Load is called.
783 // Call CompleteLoadingAndWait to cause the load to complete.
784 void WaitForLoadCall() {
787 // Verify that PeristentStore::Load was called.
788 testing::Mock::VerifyAndClear(persistent_store_
.get());
791 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
792 // and PersistentCookieStore::Load completion callback and waits
793 // until the message loop is quit.
794 void CompleteLoadingAndWait() {
795 while (!loaded_for_key_callbacks_
.empty()) {
796 loaded_for_key_callbacks_
.front().Run(loaded_cookies_
);
797 loaded_cookies_
.clear();
798 loaded_for_key_callbacks_
.pop();
801 loaded_callback_
.Run(loaded_cookies_
);
805 // Performs the provided action, expecting it to cause a call to
806 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call
808 void BeginWith(testing::Action
<void(void)> action
) {
809 EXPECT_CALL(*this, Begin()).WillOnce(action
);
814 void BeginWithForDomainKey(std::string key
,
815 testing::Action
<void(void)> action
) {
816 EXPECT_CALL(*this, Begin()).WillOnce(action
);
818 ExpectLoadForKeyCall(key
, false);
822 // Declares an expectation that PersistentCookieStore::Load will be called,
823 // saving the provided callback and sending a quit to the message loop.
824 void ExpectLoadCall() {
825 EXPECT_CALL(*persistent_store_
.get(), Load(testing::_
))
826 .WillOnce(testing::DoAll(testing::SaveArg
<0>(&loaded_callback_
),
827 QuitCurrentMessageLoop()));
830 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
831 // will be called, saving the provided callback and sending a quit to the
833 void ExpectLoadForKeyCall(std::string key
, bool quit_queue
) {
835 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
837 testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_
),
838 QuitCurrentMessageLoop()));
840 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
841 .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_
));
844 // Invokes the initial action.
845 MOCK_METHOD0(Begin
, void(void));
847 // Returns the CookieMonster instance under test.
848 CookieMonster
& cookie_monster() { return *cookie_monster_
.get(); }
851 // Declares that mock expectations in this test suite are strictly ordered.
852 testing::InSequence in_sequence_
;
853 // Holds cookies to be returned from PersistentCookieStore::Load or
854 // PersistentCookieStore::LoadCookiesForKey.
855 std::vector
<CanonicalCookie
*> loaded_cookies_
;
856 // Stores the callback passed from the CookieMonster to the
857 // PersistentCookieStore::Load
858 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_
;
859 // Stores the callback passed from the CookieMonster to the
860 // PersistentCookieStore::LoadCookiesForKey
861 std::queue
<CookieMonster::PersistentCookieStore::LoadedCallback
>
862 loaded_for_key_callbacks_
;
864 // Stores the CookieMonster under test.
865 scoped_refptr
<CookieMonster
> cookie_monster_
;
866 // Stores the mock PersistentCookieStore.
867 scoped_refptr
<NewMockPersistentCookieStore
> persistent_store_
;
870 TEST_F(DeferredCookieTaskTest
, DeferredGetCookies
) {
871 DeclareLoadedCookie("www.google.izzle",
872 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
873 Time::Now() + TimeDelta::FromDays(3));
875 MockGetCookiesCallback get_cookies_callback
;
877 BeginWithForDomainKey("google.izzle", GetCookiesAction(
878 &cookie_monster(), url_google_
, &get_cookies_callback
));
882 EXPECT_CALL(get_cookies_callback
, Invoke("X=1")).WillOnce(
883 GetCookiesAction(&cookie_monster(), url_google_
, &get_cookies_callback
));
884 EXPECT_CALL(get_cookies_callback
, Invoke("X=1")).WillOnce(
885 QuitCurrentMessageLoop());
887 CompleteLoadingAndWait();
890 TEST_F(DeferredCookieTaskTest
, DeferredSetCookie
) {
891 MockSetCookiesCallback set_cookies_callback
;
893 BeginWithForDomainKey("google.izzle", SetCookieAction(
894 &cookie_monster(), url_google_
, "A=B", &set_cookies_callback
));
898 EXPECT_CALL(set_cookies_callback
, Invoke(true)).WillOnce(
900 &cookie_monster(), url_google_
, "X=Y", &set_cookies_callback
));
901 EXPECT_CALL(set_cookies_callback
, Invoke(true)).WillOnce(
902 QuitCurrentMessageLoop());
904 CompleteLoadingAndWait();
907 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCookie
) {
908 MockClosure delete_cookie_callback
;
910 BeginWithForDomainKey("google.izzle", DeleteCookieAction(
911 &cookie_monster(), url_google_
, "A", &delete_cookie_callback
));
915 EXPECT_CALL(delete_cookie_callback
, Invoke()).WillOnce(
917 &cookie_monster(), url_google_
, "X", &delete_cookie_callback
));
918 EXPECT_CALL(delete_cookie_callback
, Invoke()).WillOnce(
919 QuitCurrentMessageLoop());
921 CompleteLoadingAndWait();
924 TEST_F(DeferredCookieTaskTest
, DeferredSetCookieWithDetails
) {
925 MockSetCookiesCallback set_cookies_callback
;
927 CookiesInputInfo cookie_info
= {
928 url_google_foo_
, "A", "B", std::string(), "/foo",
929 base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
931 BeginWithForDomainKey("google.izzle", SetCookieWithDetailsAction(
932 &cookie_monster(), cookie_info
, &set_cookies_callback
));
936 CookiesInputInfo cookie_info_exp
= {
937 url_google_foo_
, "A", "B", std::string(), "/foo",
938 base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
940 EXPECT_CALL(set_cookies_callback
, Invoke(true)).WillOnce(
941 SetCookieWithDetailsAction(
942 &cookie_monster(), cookie_info_exp
, &set_cookies_callback
));
943 EXPECT_CALL(set_cookies_callback
, Invoke(true)).WillOnce(
944 QuitCurrentMessageLoop());
946 CompleteLoadingAndWait();
949 TEST_F(DeferredCookieTaskTest
, DeferredGetAllCookies
) {
950 DeclareLoadedCookie("www.google.izzle",
951 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
952 Time::Now() + TimeDelta::FromDays(3));
954 MockGetCookieListCallback get_cookie_list_callback
;
956 BeginWith(GetAllCookiesAction(
957 &cookie_monster(), &get_cookie_list_callback
));
961 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
)).WillOnce(
962 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback
));
963 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
)).WillOnce(
964 QuitCurrentMessageLoop());
966 CompleteLoadingAndWait();
969 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlCookies
) {
970 DeclareLoadedCookie("www.google.izzle",
971 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
972 Time::Now() + TimeDelta::FromDays(3));
974 MockGetCookieListCallback get_cookie_list_callback
;
976 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlAction(
977 &cookie_monster(), url_google_
, &get_cookie_list_callback
));
981 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
)).WillOnce(
982 GetAllCookiesForUrlAction(
983 &cookie_monster(), url_google_
, &get_cookie_list_callback
));
984 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
)).WillOnce(
985 QuitCurrentMessageLoop());
987 CompleteLoadingAndWait();
990 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlWithOptionsCookies
) {
991 DeclareLoadedCookie("www.google.izzle",
992 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
993 Time::Now() + TimeDelta::FromDays(3));
995 MockGetCookieListCallback get_cookie_list_callback
;
997 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
998 &cookie_monster(), url_google_
, &get_cookie_list_callback
));
1002 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
)).WillOnce(
1003 GetAllCookiesForUrlWithOptionsAction(
1004 &cookie_monster(), url_google_
, &get_cookie_list_callback
));
1005 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
)).WillOnce(
1006 QuitCurrentMessageLoop());
1008 CompleteLoadingAndWait();
1011 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCookies
) {
1012 MockDeleteCallback delete_callback
;
1014 BeginWith(DeleteAllAction(
1015 &cookie_monster(), &delete_callback
));
1019 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1020 DeleteAllAction(&cookie_monster(), &delete_callback
));
1021 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1022 QuitCurrentMessageLoop());
1024 CompleteLoadingAndWait();
1027 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCreatedBetweenCookies
) {
1028 MockDeleteCallback delete_callback
;
1030 BeginWith(DeleteAllCreatedBetweenAction(
1031 &cookie_monster(), base::Time(), base::Time::Now(), &delete_callback
));
1035 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1036 DeleteAllCreatedBetweenAction(
1037 &cookie_monster(), base::Time(), base::Time::Now(),
1039 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1040 QuitCurrentMessageLoop());
1042 CompleteLoadingAndWait();
1045 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllForHostCookies
) {
1046 MockDeleteCallback delete_callback
;
1048 BeginWithForDomainKey("google.izzle", DeleteAllForHostAction(
1049 &cookie_monster(), url_google_
, &delete_callback
));
1053 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1054 DeleteAllForHostAction(
1055 &cookie_monster(), url_google_
, &delete_callback
));
1056 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1057 QuitCurrentMessageLoop());
1059 CompleteLoadingAndWait();
1062 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCanonicalCookie
) {
1063 std::vector
<CanonicalCookie
*> cookies
;
1064 CanonicalCookie cookie
= BuildCanonicalCookie(
1065 "www.google.com", "X=1; path=/", base::Time::Now());
1067 MockDeleteCookieCallback delete_cookie_callback
;
1069 BeginWith(DeleteCanonicalCookieAction(
1070 &cookie_monster(), cookie
, &delete_cookie_callback
));
1074 EXPECT_CALL(delete_cookie_callback
, Invoke(false)).WillOnce(
1075 DeleteCanonicalCookieAction(
1076 &cookie_monster(), cookie
, &delete_cookie_callback
));
1077 EXPECT_CALL(delete_cookie_callback
, Invoke(false)).WillOnce(
1078 QuitCurrentMessageLoop());
1080 CompleteLoadingAndWait();
1083 TEST_F(DeferredCookieTaskTest
, DeferredDeleteSessionCookies
) {
1084 MockDeleteCallback delete_callback
;
1086 BeginWith(DeleteSessionCookiesAction(
1087 &cookie_monster(), &delete_callback
));
1091 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1092 DeleteSessionCookiesAction(&cookie_monster(), &delete_callback
));
1093 EXPECT_CALL(delete_callback
, Invoke(false)).WillOnce(
1094 QuitCurrentMessageLoop());
1096 CompleteLoadingAndWait();
1099 // Verify that a series of queued tasks are executed in order upon loading of
1100 // the backing store and that new tasks received while the queued tasks are
1101 // being dispatched go to the end of the queue.
1102 TEST_F(DeferredCookieTaskTest
, DeferredTaskOrder
) {
1103 DeclareLoadedCookie("www.google.izzle",
1104 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1105 Time::Now() + TimeDelta::FromDays(3));
1107 MockGetCookiesCallback get_cookies_callback
;
1108 MockSetCookiesCallback set_cookies_callback
;
1109 MockGetCookiesCallback get_cookies_callback_deferred
;
1111 EXPECT_CALL(*this, Begin()).WillOnce(testing::DoAll(
1113 &cookie_monster(), url_google_
, &get_cookies_callback
),
1115 &cookie_monster(), url_google_
, "A=B", &set_cookies_callback
)));
1117 ExpectLoadForKeyCall("google.izzle", false);
1121 EXPECT_CALL(get_cookies_callback
, Invoke("X=1")).WillOnce(
1123 &cookie_monster(), url_google_
, &get_cookies_callback_deferred
));
1124 EXPECT_CALL(set_cookies_callback
, Invoke(true));
1125 EXPECT_CALL(get_cookies_callback_deferred
, Invoke("A=B; X=1")).WillOnce(
1126 QuitCurrentMessageLoop());
1128 CompleteLoadingAndWait();
1131 TEST_F(CookieMonsterTest
, TestCookieDeleteAll
) {
1132 scoped_refptr
<MockPersistentCookieStore
> store(
1133 new MockPersistentCookieStore
);
1134 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1135 CookieOptions options
;
1136 options
.set_include_httponly();
1138 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
1139 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1142 SetCookieWithOptions(cm
.get(), url_google_
, "C=D; httponly", options
));
1143 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1145 EXPECT_EQ(2, DeleteAll(cm
.get()));
1146 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1147 EXPECT_EQ(0u, store
->commands().size());
1149 // Create a persistent cookie.
1150 EXPECT_TRUE(SetCookie(
1153 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1154 ASSERT_EQ(1u, store
->commands().size());
1155 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1157 EXPECT_EQ(1, DeleteAll(cm
.get())); // sync_to_store = true.
1158 ASSERT_EQ(2u, store
->commands().size());
1159 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1161 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1164 TEST_F(CookieMonsterTest
, TestCookieDeleteAllCreatedBetweenTimestamps
) {
1165 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1166 Time now
= Time::Now();
1168 // Nothing has been added so nothing should be deleted.
1171 DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99), Time()));
1173 // Create 3 cookies with creation date of today, yesterday and the day before.
1174 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-0=Now", now
));
1175 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-1=Yesterday",
1176 now
- TimeDelta::FromDays(1)));
1177 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-2=DayBefore",
1178 now
- TimeDelta::FromDays(2)));
1179 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-3=ThreeDays",
1180 now
- TimeDelta::FromDays(3)));
1181 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-7=LastWeek",
1182 now
- TimeDelta::FromDays(7)));
1184 // Try to delete threedays and the daybefore.
1186 DeleteAllCreatedBetween(cm
.get(),
1187 now
- TimeDelta::FromDays(3),
1188 now
- TimeDelta::FromDays(1)));
1190 // Try to delete yesterday, also make sure that delete_end is not
1193 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(2), now
));
1195 // Make sure the delete_begin is inclusive.
1197 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(7), now
));
1199 // Delete the last (now) item.
1200 EXPECT_EQ(1, DeleteAllCreatedBetween(cm
.get(), Time(), Time()));
1202 // Really make sure everything is gone.
1203 EXPECT_EQ(0, DeleteAll(cm
.get()));
1206 static const int kAccessDelayMs
= kLastAccessThresholdMilliseconds
+ 20;
1208 TEST_F(CookieMonsterTest
, TestLastAccess
) {
1209 scoped_refptr
<CookieMonster
> cm(
1210 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1212 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1213 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1215 // Reading the cookie again immediately shouldn't update the access date,
1216 // since we're inside the threshold.
1217 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1218 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1220 // Reading after a short wait should update the access date.
1221 base::PlatformThread::Sleep(
1222 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1223 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1224 EXPECT_FALSE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1227 TEST_F(CookieMonsterTest
, TestHostGarbageCollection
) {
1228 TestHostGarbageCollectHelper();
1231 TEST_F(CookieMonsterTest
, TestPriorityAwareGarbageCollection
) {
1232 TestPriorityAwareGarbageCollectHelper();
1235 TEST_F(CookieMonsterTest
, TestDeleteSingleCookie
) {
1236 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1238 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1239 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1240 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1241 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1243 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1244 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1246 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1247 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1250 TEST_F(CookieMonsterTest
, SetCookieableSchemes
) {
1251 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1252 scoped_refptr
<CookieMonster
> cm_foo(new CookieMonster(NULL
, NULL
));
1254 // Only cm_foo should allow foo:// cookies.
1255 const char* kSchemes
[] = {"foo"};
1256 cm_foo
->SetCookieableSchemes(kSchemes
, 1);
1258 GURL
foo_url("foo://host/path");
1259 GURL
http_url("http://host/path");
1261 EXPECT_TRUE(SetCookie(cm
.get(), http_url
, "x=1"));
1262 EXPECT_FALSE(SetCookie(cm
.get(), foo_url
, "x=1"));
1263 EXPECT_TRUE(SetCookie(cm_foo
.get(), foo_url
, "x=1"));
1264 EXPECT_FALSE(SetCookie(cm_foo
.get(), http_url
, "x=1"));
1267 TEST_F(CookieMonsterTest
, GetAllCookiesForURL
) {
1268 scoped_refptr
<CookieMonster
> cm(
1269 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1271 // Create an httponly cookie.
1272 CookieOptions options
;
1273 options
.set_include_httponly();
1276 SetCookieWithOptions(cm
.get(), url_google_
, "A=B; httponly", options
));
1277 EXPECT_TRUE(SetCookieWithOptions(
1278 cm
.get(), url_google_
, "C=D; domain=.google.izzle", options
));
1279 EXPECT_TRUE(SetCookieWithOptions(cm
.get(),
1281 "E=F; domain=.google.izzle; secure",
1284 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1286 base::PlatformThread::Sleep(
1287 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1289 // Check cookies for url.
1290 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
1291 CookieList::iterator it
= cookies
.begin();
1293 ASSERT_TRUE(it
!= cookies
.end());
1294 EXPECT_EQ("www.google.izzle", it
->Domain());
1295 EXPECT_EQ("A", it
->Name());
1297 ASSERT_TRUE(++it
!= cookies
.end());
1298 EXPECT_EQ(".google.izzle", it
->Domain());
1299 EXPECT_EQ("C", it
->Name());
1301 ASSERT_TRUE(++it
== cookies
.end());
1303 // Check cookies for url excluding http-only cookies.
1305 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, CookieOptions());
1306 it
= cookies
.begin();
1308 ASSERT_TRUE(it
!= cookies
.end());
1309 EXPECT_EQ(".google.izzle", it
->Domain());
1310 EXPECT_EQ("C", it
->Name());
1312 ASSERT_TRUE(++it
== cookies
.end());
1314 // Test secure cookies.
1315 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1316 it
= cookies
.begin();
1318 ASSERT_TRUE(it
!= cookies
.end());
1319 EXPECT_EQ("www.google.izzle", it
->Domain());
1320 EXPECT_EQ("A", it
->Name());
1322 ASSERT_TRUE(++it
!= cookies
.end());
1323 EXPECT_EQ(".google.izzle", it
->Domain());
1324 EXPECT_EQ("C", it
->Name());
1326 ASSERT_TRUE(++it
!= cookies
.end());
1327 EXPECT_EQ(".google.izzle", it
->Domain());
1328 EXPECT_EQ("E", it
->Name());
1330 ASSERT_TRUE(++it
== cookies
.end());
1332 // Reading after a short wait should not update the access date.
1333 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1336 TEST_F(CookieMonsterTest
, GetAllCookiesForURLPathMatching
) {
1337 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1338 CookieOptions options
;
1340 EXPECT_TRUE(SetCookieWithOptions(
1341 cm
.get(), url_google_foo_
, "A=B; path=/foo;", options
));
1342 EXPECT_TRUE(SetCookieWithOptions(
1343 cm
.get(), url_google_bar_
, "C=D; path=/bar;", options
));
1344 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "E=F;", options
));
1346 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1347 CookieList::iterator it
= cookies
.begin();
1349 ASSERT_TRUE(it
!= cookies
.end());
1350 EXPECT_EQ("A", it
->Name());
1351 EXPECT_EQ("/foo", it
->Path());
1353 ASSERT_TRUE(++it
!= cookies
.end());
1354 EXPECT_EQ("E", it
->Name());
1355 EXPECT_EQ("/", it
->Path());
1357 ASSERT_TRUE(++it
== cookies
.end());
1359 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1360 it
= cookies
.begin();
1362 ASSERT_TRUE(it
!= cookies
.end());
1363 EXPECT_EQ("C", it
->Name());
1364 EXPECT_EQ("/bar", it
->Path());
1366 ASSERT_TRUE(++it
!= cookies
.end());
1367 EXPECT_EQ("E", it
->Name());
1368 EXPECT_EQ("/", it
->Path());
1370 ASSERT_TRUE(++it
== cookies
.end());
1373 TEST_F(CookieMonsterTest
, DeleteCookieByName
) {
1374 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1376 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A1; path=/"));
1377 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A2; path=/foo"));
1378 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A3; path=/bar"));
1379 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B1; path=/"));
1380 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B2; path=/foo"));
1381 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B3; path=/bar"));
1383 DeleteCookie(cm
.get(), GURL(std::string(kUrlGoogle
) + "/foo/bar"), "A");
1385 CookieList cookies
= GetAllCookies(cm
.get());
1386 size_t expected_size
= 4;
1387 EXPECT_EQ(expected_size
, cookies
.size());
1388 for (CookieList::iterator it
= cookies
.begin();
1389 it
!= cookies
.end(); ++it
) {
1390 EXPECT_NE("A1", it
->Value());
1391 EXPECT_NE("A2", it
->Value());
1395 TEST_F(CookieMonsterTest
, ImportCookiesFromCookieMonster
) {
1396 scoped_refptr
<CookieMonster
> cm_1(new CookieMonster(NULL
, NULL
));
1397 CookieOptions options
;
1399 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_foo_
,
1402 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_bar_
,
1405 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_
,
1409 CookieList cookies_1
= GetAllCookies(cm_1
.get());
1410 scoped_refptr
<CookieMonster
> cm_2(new CookieMonster(NULL
, NULL
));
1411 ASSERT_TRUE(cm_2
->ImportCookies(cookies_1
));
1412 CookieList cookies_2
= GetAllCookies(cm_2
.get());
1414 size_t expected_size
= 3;
1415 EXPECT_EQ(expected_size
, cookies_2
.size());
1417 CookieList::iterator it
= cookies_2
.begin();
1419 ASSERT_TRUE(it
!= cookies_2
.end());
1420 EXPECT_EQ("A1", it
->Name());
1421 EXPECT_EQ("/foo", it
->Path());
1423 ASSERT_TRUE(++it
!= cookies_2
.end());
1424 EXPECT_EQ("A2", it
->Name());
1425 EXPECT_EQ("/bar", it
->Path());
1427 ASSERT_TRUE(++it
!= cookies_2
.end());
1428 EXPECT_EQ("A3", it
->Name());
1429 EXPECT_EQ("/", it
->Path());
1432 // Tests importing from a persistent cookie store that contains duplicate
1433 // equivalent cookies. This situation should be handled by removing the
1434 // duplicate cookie (both from the in-memory cache, and from the backing store).
1436 // This is a regression test for: http://crbug.com/17855.
1437 TEST_F(CookieMonsterTest
, DontImportDuplicateCookies
) {
1438 scoped_refptr
<MockPersistentCookieStore
> store(
1439 new MockPersistentCookieStore
);
1441 // We will fill some initial cookies into the PersistentCookieStore,
1442 // to simulate a database with 4 duplicates. Note that we need to
1443 // be careful not to have any duplicate creation times at all (as it's a
1444 // violation of a CookieMonster invariant) even if Time::Now() doesn't
1445 // move between calls.
1446 std::vector
<CanonicalCookie
*> initial_cookies
;
1448 // Insert 4 cookies with name "X" on path "/", with varying creation
1449 // dates. We expect only the most recent one to be preserved following
1452 AddCookieToList("www.google.com",
1453 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1454 Time::Now() + TimeDelta::FromDays(3),
1457 AddCookieToList("www.google.com",
1458 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1459 Time::Now() + TimeDelta::FromDays(1),
1462 // ===> This one is the WINNER (biggest creation time). <====
1463 AddCookieToList("www.google.com",
1464 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1465 Time::Now() + TimeDelta::FromDays(4),
1468 AddCookieToList("www.google.com",
1469 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1473 // Insert 2 cookies with name "X" on path "/2", with varying creation
1474 // dates. We expect only the most recent one to be preserved the import.
1476 // ===> This one is the WINNER (biggest creation time). <====
1477 AddCookieToList("www.google.com",
1478 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1479 Time::Now() + TimeDelta::FromDays(9),
1482 AddCookieToList("www.google.com",
1483 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1484 Time::Now() + TimeDelta::FromDays(2),
1487 // Insert 1 cookie with name "Y" on path "/".
1488 AddCookieToList("www.google.com",
1489 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1490 Time::Now() + TimeDelta::FromDays(10),
1493 // Inject our initial cookies into the mock PersistentCookieStore.
1494 store
->SetLoadExpectation(true, initial_cookies
);
1496 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1498 // Verify that duplicates were not imported for path "/".
1499 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1500 EXPECT_EQ("X=3; Y=a", GetCookies(cm
.get(), GURL("http://www.google.com/")));
1502 // Verify that same-named cookie on a different path ("/x2") didn't get
1504 EXPECT_EQ("X=a1; X=3; Y=a",
1505 GetCookies(cm
.get(), GURL("http://www.google.com/2/x")));
1507 // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1508 ASSERT_EQ(4u, store
->commands().size());
1509 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[0].type
);
1510 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1511 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[2].type
);
1512 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
1515 // Tests importing from a persistent cookie store that contains cookies
1516 // with duplicate creation times. This situation should be handled by
1517 // dropping the cookies before insertion/visibility to user.
1519 // This is a regression test for: http://crbug.com/43188.
1520 TEST_F(CookieMonsterTest
, DontImportDuplicateCreationTimes
) {
1521 scoped_refptr
<MockPersistentCookieStore
> store(
1522 new MockPersistentCookieStore
);
1524 Time
now(Time::Now());
1525 Time
earlier(now
- TimeDelta::FromDays(1));
1527 // Insert 8 cookies, four with the current time as creation times, and
1528 // four with the earlier time as creation times. We should only get
1529 // two cookies remaining, but which two (other than that there should
1530 // be one from each set) will be random.
1531 std::vector
<CanonicalCookie
*> initial_cookies
;
1532 AddCookieToList("www.google.com", "X=1; path=/", now
, &initial_cookies
);
1533 AddCookieToList("www.google.com", "X=2; path=/", now
, &initial_cookies
);
1534 AddCookieToList("www.google.com", "X=3; path=/", now
, &initial_cookies
);
1535 AddCookieToList("www.google.com", "X=4; path=/", now
, &initial_cookies
);
1537 AddCookieToList("www.google.com", "Y=1; path=/", earlier
, &initial_cookies
);
1538 AddCookieToList("www.google.com", "Y=2; path=/", earlier
, &initial_cookies
);
1539 AddCookieToList("www.google.com", "Y=3; path=/", earlier
, &initial_cookies
);
1540 AddCookieToList("www.google.com", "Y=4; path=/", earlier
, &initial_cookies
);
1542 // Inject our initial cookies into the mock PersistentCookieStore.
1543 store
->SetLoadExpectation(true, initial_cookies
);
1545 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1547 CookieList
list(GetAllCookies(cm
.get()));
1548 EXPECT_EQ(2U, list
.size());
1549 // Confirm that we have one of each.
1550 std::string
name1(list
[0].Name());
1551 std::string
name2(list
[1].Name());
1552 EXPECT_TRUE(name1
== "X" || name2
== "X");
1553 EXPECT_TRUE(name1
== "Y" || name2
== "Y");
1554 EXPECT_NE(name1
, name2
);
1557 TEST_F(CookieMonsterTest
, CookieMonsterDelegate
) {
1558 scoped_refptr
<MockPersistentCookieStore
> store(
1559 new MockPersistentCookieStore
);
1560 scoped_refptr
<MockCookieMonsterDelegate
> delegate(
1561 new MockCookieMonsterDelegate
);
1562 scoped_refptr
<CookieMonster
> cm(
1563 new CookieMonster(store
.get(), delegate
.get()));
1565 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1566 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1567 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1568 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1569 ASSERT_EQ(3u, delegate
->changes().size());
1570 EXPECT_FALSE(delegate
->changes()[0].second
);
1571 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1572 EXPECT_EQ("A", delegate
->changes()[0].first
.Name());
1573 EXPECT_EQ("B", delegate
->changes()[0].first
.Value());
1574 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1575 EXPECT_FALSE(delegate
->changes()[1].second
);
1576 EXPECT_EQ("C", delegate
->changes()[1].first
.Name());
1577 EXPECT_EQ("D", delegate
->changes()[1].first
.Value());
1578 EXPECT_EQ(url_google_
.host(), delegate
->changes()[2].first
.Domain());
1579 EXPECT_FALSE(delegate
->changes()[2].second
);
1580 EXPECT_EQ("E", delegate
->changes()[2].first
.Name());
1581 EXPECT_EQ("F", delegate
->changes()[2].first
.Value());
1584 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1585 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1586 ASSERT_EQ(1u, delegate
->changes().size());
1587 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1588 EXPECT_TRUE(delegate
->changes()[0].second
);
1589 EXPECT_EQ("C", delegate
->changes()[0].first
.Name());
1590 EXPECT_EQ("D", delegate
->changes()[0].first
.Value());
1593 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1594 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1595 EXPECT_EQ(0u, delegate
->changes().size());
1597 // Insert a cookie "a" for path "/path1"
1598 EXPECT_TRUE(SetCookie(cm
.get(),
1600 "a=val1; path=/path1; "
1601 "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1602 ASSERT_EQ(1u, store
->commands().size());
1603 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1604 ASSERT_EQ(1u, delegate
->changes().size());
1605 EXPECT_FALSE(delegate
->changes()[0].second
);
1606 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1607 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1608 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1611 // Insert a cookie "a" for path "/path1", that is httponly. This should
1612 // overwrite the non-http-only version.
1613 CookieOptions allow_httponly
;
1614 allow_httponly
.set_include_httponly();
1615 EXPECT_TRUE(SetCookieWithOptions(cm
.get(),
1617 "a=val2; path=/path1; httponly; "
1618 "expires=Mon, 18-Apr-22 22:50:14 GMT",
1620 ASSERT_EQ(3u, store
->commands().size());
1621 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1622 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
1623 ASSERT_EQ(2u, delegate
->changes().size());
1624 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1625 EXPECT_TRUE(delegate
->changes()[0].second
);
1626 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1627 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1628 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1629 EXPECT_FALSE(delegate
->changes()[1].second
);
1630 EXPECT_EQ("a", delegate
->changes()[1].first
.Name());
1631 EXPECT_EQ("val2", delegate
->changes()[1].first
.Value());
1635 TEST_F(CookieMonsterTest
, SetCookieWithDetails
) {
1636 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1638 EXPECT_TRUE(SetCookieWithDetails(cm
.get(),
1647 COOKIE_PRIORITY_DEFAULT
));
1648 EXPECT_TRUE(SetCookieWithDetails(cm
.get(),
1657 COOKIE_PRIORITY_DEFAULT
));
1658 EXPECT_TRUE(SetCookieWithDetails(cm
.get(),
1667 COOKIE_PRIORITY_DEFAULT
));
1669 // Test that malformed attributes fail to set the cookie.
1670 EXPECT_FALSE(SetCookieWithDetails(cm
.get(),
1679 COOKIE_PRIORITY_DEFAULT
));
1680 EXPECT_FALSE(SetCookieWithDetails(cm
.get(),
1689 COOKIE_PRIORITY_DEFAULT
));
1690 EXPECT_FALSE(SetCookieWithDetails(cm
.get(),
1699 COOKIE_PRIORITY_DEFAULT
));
1700 EXPECT_FALSE(SetCookieWithDetails(cm
.get(),
1709 COOKIE_PRIORITY_DEFAULT
));
1710 EXPECT_FALSE(SetCookieWithDetails(cm
.get(),
1719 COOKIE_PRIORITY_DEFAULT
));
1721 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1722 CookieList::iterator it
= cookies
.begin();
1724 ASSERT_TRUE(it
!= cookies
.end());
1725 EXPECT_EQ("A", it
->Name());
1726 EXPECT_EQ("B", it
->Value());
1727 EXPECT_EQ("www.google.izzle", it
->Domain());
1728 EXPECT_EQ("/foo", it
->Path());
1729 EXPECT_FALSE(it
->IsPersistent());
1730 EXPECT_FALSE(it
->IsSecure());
1731 EXPECT_FALSE(it
->IsHttpOnly());
1733 ASSERT_TRUE(++it
== cookies
.end());
1735 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1736 it
= cookies
.begin();
1738 ASSERT_TRUE(it
!= cookies
.end());
1739 EXPECT_EQ("C", it
->Name());
1740 EXPECT_EQ("D", it
->Value());
1741 EXPECT_EQ(".google.izzle", it
->Domain());
1742 EXPECT_EQ("/bar", it
->Path());
1743 EXPECT_FALSE(it
->IsSecure());
1744 EXPECT_TRUE(it
->IsHttpOnly());
1746 ASSERT_TRUE(++it
== cookies
.end());
1748 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1749 it
= cookies
.begin();
1751 ASSERT_TRUE(it
!= cookies
.end());
1752 EXPECT_EQ("E", it
->Name());
1753 EXPECT_EQ("F", it
->Value());
1754 EXPECT_EQ("/", it
->Path());
1755 EXPECT_EQ("www.google.izzle", it
->Domain());
1756 EXPECT_TRUE(it
->IsSecure());
1757 EXPECT_FALSE(it
->IsHttpOnly());
1759 ASSERT_TRUE(++it
== cookies
.end());
1762 TEST_F(CookieMonsterTest
, DeleteAllForHost
) {
1763 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1766 // * Non-secure URL, mid-level (http://w.c.b.a)
1767 // * Secure URL, mid-level (https://w.c.b.a)
1768 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1769 // All three tests should nuke only the midlevel host cookie,
1770 // the http_only cookie, the host secure cookie, and the two host
1771 // path cookies. http_only, secure, and paths are ignored by
1772 // this call, and domain cookies arent touched.
1773 PopulateCmForDeleteAllForHost(cm
);
1774 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1775 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1776 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1777 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1778 EXPECT_EQ("dom_1=X; host_1=X",
1779 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1780 EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1781 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1782 GetCookies(cm
.get(),
1783 GURL(kTopLevelDomainPlus2Secure
+
1784 std::string("/dir1/dir2/xxx"))));
1786 EXPECT_EQ(5, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2
)));
1787 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1789 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1790 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1791 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1792 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1793 EXPECT_EQ("dom_1=X; host_1=X",
1794 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1795 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1796 GetCookies(cm
.get(),
1797 GURL(kTopLevelDomainPlus2Secure
+
1798 std::string("/dir1/dir2/xxx"))));
1800 PopulateCmForDeleteAllForHost(cm
);
1801 EXPECT_EQ(5, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1802 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1804 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1805 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1806 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1807 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1808 EXPECT_EQ("dom_1=X; host_1=X",
1809 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1810 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1811 GetCookies(cm
.get(),
1812 GURL(kTopLevelDomainPlus2Secure
+
1813 std::string("/dir1/dir2/xxx"))));
1815 PopulateCmForDeleteAllForHost(cm
);
1819 GURL(kTopLevelDomainPlus2Secure
+ std::string("/dir1/xxx"))));
1820 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1822 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1823 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1824 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1825 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1826 EXPECT_EQ("dom_1=X; host_1=X",
1827 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1828 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1829 GetCookies(cm
.get(),
1830 GURL(kTopLevelDomainPlus2Secure
+
1831 std::string("/dir1/dir2/xxx"))));
1834 TEST_F(CookieMonsterTest
, UniqueCreationTime
) {
1835 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1836 CookieOptions options
;
1838 // Add in three cookies through every public interface to the
1839 // CookieMonster and confirm that none of them have duplicate
1842 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1843 // are not included as they aren't going to be public for very much
1846 // SetCookie, SetCookieWithOptions, SetCookieWithDetails
1848 SetCookie(cm
.get(), url_google_
, "SetCookie1=A");
1849 SetCookie(cm
.get(), url_google_
, "SetCookie2=A");
1850 SetCookie(cm
.get(), url_google_
, "SetCookie3=A");
1852 SetCookieWithOptions(
1853 cm
.get(), url_google_
, "setCookieWithOptions1=A", options
);
1854 SetCookieWithOptions(
1855 cm
.get(), url_google_
, "setCookieWithOptions2=A", options
);
1856 SetCookieWithOptions(
1857 cm
.get(), url_google_
, "setCookieWithOptions3=A", options
);
1859 SetCookieWithDetails(cm
.get(),
1861 "setCookieWithDetails1",
1868 COOKIE_PRIORITY_DEFAULT
);
1869 SetCookieWithDetails(cm
.get(),
1871 "setCookieWithDetails2",
1878 COOKIE_PRIORITY_DEFAULT
);
1879 SetCookieWithDetails(cm
.get(),
1881 "setCookieWithDetails3",
1888 COOKIE_PRIORITY_DEFAULT
);
1891 CookieList
cookie_list(GetAllCookies(cm
.get()));
1892 typedef std::map
<int64
, CanonicalCookie
> TimeCookieMap
;
1893 TimeCookieMap check_map
;
1894 for (CookieList::const_iterator it
= cookie_list
.begin();
1895 it
!= cookie_list
.end(); it
++) {
1896 const int64 creation_date
= it
->CreationDate().ToInternalValue();
1897 TimeCookieMap::const_iterator
1898 existing_cookie_it(check_map
.find(creation_date
));
1899 EXPECT_TRUE(existing_cookie_it
== check_map
.end())
1900 << "Cookie " << it
->Name() << " has same creation date ("
1901 << it
->CreationDate().ToInternalValue()
1902 << ") as previously entered cookie "
1903 << existing_cookie_it
->second
.Name();
1905 if (existing_cookie_it
== check_map
.end()) {
1906 check_map
.insert(TimeCookieMap::value_type(
1907 it
->CreationDate().ToInternalValue(), *it
));
1912 // Mainly a test of GetEffectiveDomain, or more specifically, of the
1913 // expected behavior of GetEffectiveDomain within the CookieMonster.
1914 TEST_F(CookieMonsterTest
, GetKey
) {
1915 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1917 // This test is really only interesting if GetKey() actually does something.
1918 EXPECT_EQ("google.com", cm
->GetKey("www.google.com"));
1919 EXPECT_EQ("google.izzie", cm
->GetKey("www.google.izzie"));
1920 EXPECT_EQ("google.izzie", cm
->GetKey(".google.izzie"));
1921 EXPECT_EQ("bbc.co.uk", cm
->GetKey("bbc.co.uk"));
1922 EXPECT_EQ("bbc.co.uk", cm
->GetKey("a.b.c.d.bbc.co.uk"));
1923 EXPECT_EQ("apple.com", cm
->GetKey("a.b.c.d.apple.com"));
1924 EXPECT_EQ("apple.izzie", cm
->GetKey("a.b.c.d.apple.izzie"));
1926 // Cases where the effective domain is null, so we use the host
1928 EXPECT_EQ("co.uk", cm
->GetKey("co.uk"));
1929 const std::string
extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1930 EXPECT_EQ(extension_name
, cm
->GetKey(extension_name
));
1931 EXPECT_EQ("com", cm
->GetKey("com"));
1932 EXPECT_EQ("hostalias", cm
->GetKey("hostalias"));
1933 EXPECT_EQ("localhost", cm
->GetKey("localhost"));
1936 // Test that cookies transfer from/to the backing store correctly.
1937 TEST_F(CookieMonsterTest
, BackingStoreCommunication
) {
1938 // Store details for cookies transforming through the backing store interface.
1940 base::Time
current(base::Time::Now());
1941 scoped_refptr
<MockSimplePersistentCookieStore
> store(
1942 new MockSimplePersistentCookieStore
);
1943 base::Time new_access_time
;
1944 base::Time
expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1946 const CookiesInputInfo input_info
[] = {
1947 {GURL("http://a.b.google.com"), "a", "1", "", "/path/to/cookie", expires
,
1948 false, false, COOKIE_PRIORITY_DEFAULT
},
1949 {GURL("https://www.google.com"), "b", "2", ".google.com",
1950 "/path/from/cookie", expires
+ TimeDelta::FromSeconds(10),
1951 true, true, COOKIE_PRIORITY_DEFAULT
},
1952 {GURL("https://google.com"), "c", "3", "", "/another/path/to/cookie",
1953 base::Time::Now() + base::TimeDelta::FromSeconds(100),
1954 true, false, COOKIE_PRIORITY_DEFAULT
}
1956 const int INPUT_DELETE
= 1;
1958 // Create new cookies and flush them to the store.
1960 scoped_refptr
<CookieMonster
> cmout(new CookieMonster(store
.get(), NULL
));
1961 for (const CookiesInputInfo
* p
= input_info
;
1962 p
< &input_info
[arraysize(input_info
)];
1964 EXPECT_TRUE(SetCookieWithDetails(cmout
.get(),
1975 GURL
del_url(input_info
[INPUT_DELETE
].url
.Resolve(
1976 input_info
[INPUT_DELETE
].path
).spec());
1977 DeleteCookie(cmout
.get(), del_url
, input_info
[INPUT_DELETE
].name
);
1980 // Create a new cookie monster and make sure that everything is correct
1982 scoped_refptr
<CookieMonster
> cmin(new CookieMonster(store
.get(), NULL
));
1983 CookieList
cookies(GetAllCookies(cmin
.get()));
1984 ASSERT_EQ(2u, cookies
.size());
1985 // Ordering is path length, then creation time. So second cookie
1986 // will come first, and we need to swap them.
1987 std::swap(cookies
[0], cookies
[1]);
1988 for (int output_index
= 0; output_index
< 2; output_index
++) {
1989 int input_index
= output_index
* 2;
1990 const CookiesInputInfo
* input
= &input_info
[input_index
];
1991 const CanonicalCookie
* output
= &cookies
[output_index
];
1993 EXPECT_EQ(input
->name
, output
->Name());
1994 EXPECT_EQ(input
->value
, output
->Value());
1995 EXPECT_EQ(input
->url
.host(), output
->Domain());
1996 EXPECT_EQ(input
->path
, output
->Path());
1997 EXPECT_LE(current
.ToInternalValue(),
1998 output
->CreationDate().ToInternalValue());
1999 EXPECT_EQ(input
->secure
, output
->IsSecure());
2000 EXPECT_EQ(input
->http_only
, output
->IsHttpOnly());
2001 EXPECT_TRUE(output
->IsPersistent());
2002 EXPECT_EQ(input
->expiration_time
.ToInternalValue(),
2003 output
->ExpiryDate().ToInternalValue());
2008 TEST_F(CookieMonsterTest
, CookieListOrdering
) {
2009 // Put a random set of cookies into a monster and make sure
2010 // they're returned in the right order.
2011 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2013 SetCookie(cm
.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1"));
2014 EXPECT_TRUE(SetCookie(cm
.get(),
2015 GURL("http://b.a.google.com/aa/bb/cc/x.html"),
2016 "d=1; domain=b.a.google.com"));
2017 EXPECT_TRUE(SetCookie(cm
.get(),
2018 GURL("http://b.a.google.com/aa/bb/cc/x.html"),
2019 "a=4; domain=b.a.google.com"));
2020 EXPECT_TRUE(SetCookie(cm
.get(),
2021 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
2022 "e=1; domain=c.b.a.google.com"));
2023 EXPECT_TRUE(SetCookie(
2024 cm
.get(), GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1"));
2025 EXPECT_TRUE(SetCookie(
2026 cm
.get(), GURL("http://news.bbc.co.uk/midpath/x.html"), "g=10"));
2029 CookieList
cookies(GetAllCookiesForURL(
2030 cm
.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
2031 ASSERT_EQ(5u, cookies
.size());
2032 EXPECT_EQ("d", cookies
[i
++].Name());
2033 EXPECT_EQ("a", cookies
[i
++].Name());
2034 EXPECT_EQ("e", cookies
[i
++].Name());
2035 EXPECT_EQ("b", cookies
[i
++].Name());
2036 EXPECT_EQ("c", cookies
[i
++].Name());
2041 CookieList
cookies(GetAllCookies(cm
.get()));
2042 ASSERT_EQ(6u, cookies
.size());
2043 EXPECT_EQ("d", cookies
[i
++].Name());
2044 EXPECT_EQ("a", cookies
[i
++].Name());
2045 EXPECT_EQ("e", cookies
[i
++].Name());
2046 EXPECT_EQ("g", cookies
[i
++].Name());
2047 EXPECT_EQ("b", cookies
[i
++].Name());
2048 EXPECT_EQ("c", cookies
[i
++].Name());
2052 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
2053 // are somewhat complementary twins. This test is probing for whether
2054 // garbage collection always happens when it should (i.e. that we actually
2055 // get rid of cookies when we should). The perftest is probing for
2056 // whether garbage collection happens when it shouldn't. See comments
2057 // before that test for more details.
2059 // Disabled on Windows, see crbug.com/126095
2061 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers
2063 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers
2066 TEST_F(CookieMonsterTest
, MAYBE_GarbageCollectionTriggers
) {
2067 // First we check to make sure that a whole lot of recent cookies
2068 // doesn't get rid of anything after garbage collection is checked for.
2070 scoped_refptr
<CookieMonster
> cm(
2071 CreateMonsterForGC(CookieMonster::kMaxCookies
* 2));
2072 EXPECT_EQ(CookieMonster::kMaxCookies
* 2, GetAllCookies(cm
.get()).size());
2073 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
2074 EXPECT_EQ(CookieMonster::kMaxCookies
* 2 + 1,
2075 GetAllCookies(cm
.get()).size());
2078 // Now we explore a series of relationships between cookie last access
2079 // time and size of store to make sure we only get rid of cookies when
2080 // we really should.
2081 const struct TestCase
{
2083 size_t num_old_cookies
;
2084 size_t expected_initial_cookies
;
2085 // Indexed by ExpiryAndKeyScheme
2086 size_t expected_cookies_after_set
;
2089 // A whole lot of recent cookies; gc shouldn't happen.
2090 CookieMonster::kMaxCookies
* 2,
2092 CookieMonster::kMaxCookies
* 2,
2093 CookieMonster::kMaxCookies
* 2 + 1
2095 // Some old cookies, but still overflowing max.
2096 CookieMonster::kMaxCookies
* 2,
2097 CookieMonster::kMaxCookies
/ 2,
2098 CookieMonster::kMaxCookies
* 2,
2099 CookieMonster::kMaxCookies
* 2 - CookieMonster::kMaxCookies
/ 2 + 1
2101 // Old cookies enough to bring us right down to our purge line.
2102 CookieMonster::kMaxCookies
* 2,
2103 CookieMonster::kMaxCookies
+ CookieMonster::kPurgeCookies
+ 1,
2104 CookieMonster::kMaxCookies
* 2,
2105 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
2107 // Old cookies enough to bring below our purge line (which we
2109 CookieMonster::kMaxCookies
* 2,
2110 CookieMonster::kMaxCookies
* 3 / 2,
2111 CookieMonster::kMaxCookies
* 2,
2112 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
2116 for (int ci
= 0; ci
< static_cast<int>(arraysize(test_cases
)); ++ci
) {
2117 const TestCase
*test_case
= &test_cases
[ci
];
2118 scoped_refptr
<CookieMonster
> cm(
2119 CreateMonsterFromStoreForGC(
2120 test_case
->num_cookies
, test_case
->num_old_cookies
,
2121 CookieMonster::kSafeFromGlobalPurgeDays
* 2));
2122 EXPECT_EQ(test_case
->expected_initial_cookies
,
2123 GetAllCookies(cm
.get()).size()) << "For test case " << ci
;
2125 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
2126 EXPECT_EQ(test_case
->expected_cookies_after_set
,
2127 GetAllCookies(cm
.get()).size()) << "For test case " << ci
;
2131 // This test checks that keep expired cookies flag is working.
2132 TEST_F(CookieMonsterTest
, KeepExpiredCookies
) {
2133 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2134 cm
->SetKeepExpiredCookies();
2135 CookieOptions options
;
2137 // Set a persistent cookie.
2138 ASSERT_TRUE(SetCookieWithOptions(
2141 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2144 // Get the canonical cookie.
2145 CookieList cookie_list
= GetAllCookies(cm
.get());
2146 ASSERT_EQ(1U, cookie_list
.size());
2148 // Use a past expiry date to delete the cookie.
2149 ASSERT_TRUE(SetCookieWithOptions(
2152 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2155 // Check that the cookie with the past expiry date is still there.
2156 // GetAllCookies() also triggers garbage collection.
2157 cookie_list
= GetAllCookies(cm
.get());
2158 ASSERT_EQ(1U, cookie_list
.size());
2159 ASSERT_TRUE(cookie_list
[0].IsExpired(Time::Now()));
2164 // Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2165 class FlushablePersistentStore
: public CookieMonster::PersistentCookieStore
{
2167 FlushablePersistentStore() : flush_count_(0) {}
2169 void Load(const LoadedCallback
& loaded_callback
) override
{
2170 std::vector
<CanonicalCookie
*> out_cookies
;
2171 base::MessageLoop::current()->PostTask(
2173 base::Bind(&net::LoadedCallbackTask::Run
,
2174 new net::LoadedCallbackTask(loaded_callback
, out_cookies
)));
2177 void LoadCookiesForKey(const std::string
& key
,
2178 const LoadedCallback
& loaded_callback
) override
{
2179 Load(loaded_callback
);
2182 void AddCookie(const CanonicalCookie
&) override
{}
2183 void UpdateCookieAccessTime(const CanonicalCookie
&) override
{}
2184 void DeleteCookie(const CanonicalCookie
&) override
{}
2185 void SetForceKeepSessionState() override
{}
2187 void Flush(const base::Closure
& callback
) override
{
2189 if (!callback
.is_null())
2194 return flush_count_
;
2198 ~FlushablePersistentStore() override
{}
2200 volatile int flush_count_
;
2203 // Counts the number of times Callback() has been run.
2204 class CallbackCounter
: public base::RefCountedThreadSafe
<CallbackCounter
> {
2206 CallbackCounter() : callback_count_(0) {}
2212 int callback_count() {
2213 return callback_count_
;
2217 friend class base::RefCountedThreadSafe
<CallbackCounter
>;
2218 ~CallbackCounter() {}
2220 volatile int callback_count_
;
2225 // Test that FlushStore() is forwarded to the store and callbacks are posted.
2226 TEST_F(CookieMonsterTest
, FlushStore
) {
2227 scoped_refptr
<CallbackCounter
> counter(new CallbackCounter());
2228 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2229 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2231 ASSERT_EQ(0, store
->flush_count());
2232 ASSERT_EQ(0, counter
->callback_count());
2234 // Before initialization, FlushStore() should just run the callback.
2235 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2236 base::MessageLoop::current()->RunUntilIdle();
2238 ASSERT_EQ(0, store
->flush_count());
2239 ASSERT_EQ(1, counter
->callback_count());
2241 // NULL callback is safe.
2242 cm
->FlushStore(base::Closure());
2243 base::MessageLoop::current()->RunUntilIdle();
2245 ASSERT_EQ(0, store
->flush_count());
2246 ASSERT_EQ(1, counter
->callback_count());
2248 // After initialization, FlushStore() should delegate to the store.
2249 GetAllCookies(cm
.get()); // Force init.
2250 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2251 base::MessageLoop::current()->RunUntilIdle();
2253 ASSERT_EQ(1, store
->flush_count());
2254 ASSERT_EQ(2, counter
->callback_count());
2256 // NULL callback is still safe.
2257 cm
->FlushStore(base::Closure());
2258 base::MessageLoop::current()->RunUntilIdle();
2260 ASSERT_EQ(2, store
->flush_count());
2261 ASSERT_EQ(2, counter
->callback_count());
2263 // If there's no backing store, FlushStore() is always a safe no-op.
2264 cm
= new CookieMonster(NULL
, NULL
);
2265 GetAllCookies(cm
.get()); // Force init.
2266 cm
->FlushStore(base::Closure());
2267 base::MessageLoop::current()->RunUntilIdle();
2269 ASSERT_EQ(2, counter
->callback_count());
2271 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2272 base::MessageLoop::current()->RunUntilIdle();
2274 ASSERT_EQ(3, counter
->callback_count());
2277 TEST_F(CookieMonsterTest
, HistogramCheck
) {
2278 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2279 // Should match call in InitializeHistograms, but doesn't really matter
2280 // since the histogram should have been initialized by the CM construction
2282 base::HistogramBase
* expired_histogram
=
2283 base::Histogram::FactoryGet(
2284 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2285 base::Histogram::kUmaTargetedHistogramFlag
);
2287 scoped_ptr
<base::HistogramSamples
> samples1(
2288 expired_histogram
->SnapshotSamples());
2290 SetCookieWithDetails(cm
.get(),
2291 GURL("http://fake.a.url"),
2296 base::Time::Now() + base::TimeDelta::FromMinutes(59),
2299 COOKIE_PRIORITY_DEFAULT
));
2301 scoped_ptr
<base::HistogramSamples
> samples2(
2302 expired_histogram
->SnapshotSamples());
2303 EXPECT_EQ(samples1
->TotalCount() + 1, samples2
->TotalCount());
2305 // kValidCookieLine creates a session cookie.
2306 ASSERT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
2308 scoped_ptr
<base::HistogramSamples
> samples3(
2309 expired_histogram
->SnapshotSamples());
2310 EXPECT_EQ(samples2
->TotalCount(), samples3
->TotalCount());
2315 class MultiThreadedCookieMonsterTest
: public CookieMonsterTest
{
2317 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {}
2319 // Helper methods for calling the asynchronous CookieMonster methods
2320 // from a different thread.
2322 void GetAllCookiesTask(CookieMonster
* cm
,
2323 GetCookieListCallback
* callback
) {
2324 cm
->GetAllCookiesAsync(
2325 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2328 void GetAllCookiesForURLTask(CookieMonster
* cm
,
2330 GetCookieListCallback
* callback
) {
2331 cm
->GetAllCookiesForURLAsync(
2333 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2336 void GetAllCookiesForURLWithOptionsTask(CookieMonster
* cm
,
2338 const CookieOptions
& options
,
2339 GetCookieListCallback
* callback
) {
2340 cm
->GetAllCookiesForURLWithOptionsAsync(
2342 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2345 void SetCookieWithDetailsTask(CookieMonster
* cm
, const GURL
& url
,
2346 ResultSavingCookieCallback
<bool>* callback
) {
2347 // Define the parameters here instead of in the calling fucntion.
2348 // The maximum number of parameters for Bind function is 6.
2349 std::string name
= "A";
2350 std::string value
= "B";
2351 std::string domain
= std::string();
2352 std::string path
= "/foo";
2353 base::Time expiration_time
= base::Time();
2354 bool secure
= false;
2355 bool http_only
= false;
2356 CookiePriority priority
= COOKIE_PRIORITY_DEFAULT
;
2357 cm
->SetCookieWithDetailsAsync(
2358 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
2361 &ResultSavingCookieCallback
<bool>::Run
,
2362 base::Unretained(callback
)));
2365 void DeleteAllCreatedBetweenTask(CookieMonster
* cm
,
2366 const base::Time
& delete_begin
,
2367 const base::Time
& delete_end
,
2368 ResultSavingCookieCallback
<int>* callback
) {
2369 cm
->DeleteAllCreatedBetweenAsync(
2370 delete_begin
, delete_end
,
2372 &ResultSavingCookieCallback
<int>::Run
, base::Unretained(callback
)));
2375 void DeleteAllForHostTask(CookieMonster
* cm
,
2377 ResultSavingCookieCallback
<int>* callback
) {
2378 cm
->DeleteAllForHostAsync(
2381 &ResultSavingCookieCallback
<int>::Run
, base::Unretained(callback
)));
2384 void DeleteAllCreatedBetweenForHostTask(
2386 const base::Time delete_begin
,
2387 const base::Time delete_end
,
2389 ResultSavingCookieCallback
<int>* callback
) {
2390 cm
->DeleteAllCreatedBetweenForHostAsync(
2391 delete_begin
, delete_end
, url
,
2393 &ResultSavingCookieCallback
<int>::Run
,
2394 base::Unretained(callback
)));
2397 void DeleteCanonicalCookieTask(CookieMonster
* cm
,
2398 const CanonicalCookie
& cookie
,
2399 ResultSavingCookieCallback
<bool>* callback
) {
2400 cm
->DeleteCanonicalCookieAsync(
2403 &ResultSavingCookieCallback
<bool>::Run
,
2404 base::Unretained(callback
)));
2408 void RunOnOtherThread(const base::Closure
& task
) {
2409 other_thread_
.Start();
2410 other_thread_
.message_loop()->PostTask(FROM_HERE
, task
);
2412 other_thread_
.Stop();
2415 Thread other_thread_
;
2420 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookies
) {
2421 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2422 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2423 CookieList cookies
= GetAllCookies(cm
.get());
2424 CookieList::const_iterator it
= cookies
.begin();
2425 ASSERT_TRUE(it
!= cookies
.end());
2426 EXPECT_EQ("www.google.izzle", it
->Domain());
2427 EXPECT_EQ("A", it
->Name());
2428 ASSERT_TRUE(++it
== cookies
.end());
2429 GetCookieListCallback
callback(&other_thread_
);
2430 base::Closure task
=
2431 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesTask
,
2432 base::Unretained(this),
2434 RunOnOtherThread(task
);
2435 EXPECT_TRUE(callback
.did_run());
2436 it
= callback
.cookies().begin();
2437 ASSERT_TRUE(it
!= callback
.cookies().end());
2438 EXPECT_EQ("www.google.izzle", it
->Domain());
2439 EXPECT_EQ("A", it
->Name());
2440 ASSERT_TRUE(++it
== callback
.cookies().end());
2443 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURL
) {
2444 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2445 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2446 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
2447 CookieList::const_iterator it
= cookies
.begin();
2448 ASSERT_TRUE(it
!= cookies
.end());
2449 EXPECT_EQ("www.google.izzle", it
->Domain());
2450 EXPECT_EQ("A", it
->Name());
2451 ASSERT_TRUE(++it
== cookies
.end());
2452 GetCookieListCallback
callback(&other_thread_
);
2453 base::Closure task
=
2454 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask
,
2455 base::Unretained(this),
2456 cm
, url_google_
, &callback
);
2457 RunOnOtherThread(task
);
2458 EXPECT_TRUE(callback
.did_run());
2459 it
= callback
.cookies().begin();
2460 ASSERT_TRUE(it
!= callback
.cookies().end());
2461 EXPECT_EQ("www.google.izzle", it
->Domain());
2462 EXPECT_EQ("A", it
->Name());
2463 ASSERT_TRUE(++it
== callback
.cookies().end());
2466 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURLWithOpt
) {
2467 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2468 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2469 CookieOptions options
;
2470 CookieList cookies
=
2471 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, options
);
2472 CookieList::const_iterator it
= cookies
.begin();
2473 ASSERT_TRUE(it
!= cookies
.end());
2474 EXPECT_EQ("www.google.izzle", it
->Domain());
2475 EXPECT_EQ("A", it
->Name());
2476 ASSERT_TRUE(++it
== cookies
.end());
2477 GetCookieListCallback
callback(&other_thread_
);
2478 base::Closure task
= base::Bind(
2479 &net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask
,
2480 base::Unretained(this),
2481 cm
, url_google_
, options
, &callback
);
2482 RunOnOtherThread(task
);
2483 EXPECT_TRUE(callback
.did_run());
2484 it
= callback
.cookies().begin();
2485 ASSERT_TRUE(it
!= callback
.cookies().end());
2486 EXPECT_EQ("www.google.izzle", it
->Domain());
2487 EXPECT_EQ("A", it
->Name());
2488 ASSERT_TRUE(++it
== callback
.cookies().end());
2491 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckSetCookieWithDetails
) {
2492 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2493 EXPECT_TRUE(SetCookieWithDetails(cm
.get(),
2502 COOKIE_PRIORITY_DEFAULT
));
2503 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2504 base::Closure task
= base::Bind(
2505 &net::MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask
,
2506 base::Unretained(this),
2507 cm
, url_google_foo_
, &callback
);
2508 RunOnOtherThread(task
);
2509 EXPECT_TRUE(callback
.did_run());
2510 EXPECT_TRUE(callback
.result());
2513 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllCreatedBetween
) {
2514 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2515 CookieOptions options
;
2516 Time now
= Time::Now();
2517 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2520 DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99), Time()));
2521 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2522 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2523 base::Closure task
= base::Bind(
2524 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask
,
2525 base::Unretained(this),
2526 cm
, now
- TimeDelta::FromDays(99),
2528 RunOnOtherThread(task
);
2529 EXPECT_TRUE(callback
.did_run());
2530 EXPECT_EQ(1, callback
.result());
2533 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllForHost
) {
2534 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2535 CookieOptions options
;
2536 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2537 EXPECT_EQ(1, DeleteAllForHost(cm
.get(), url_google_
));
2538 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2539 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2540 base::Closure task
= base::Bind(
2541 &net::MultiThreadedCookieMonsterTest::DeleteAllForHostTask
,
2542 base::Unretained(this),
2543 cm
, url_google_
, &callback
);
2544 RunOnOtherThread(task
);
2545 EXPECT_TRUE(callback
.did_run());
2546 EXPECT_EQ(1, callback
.result());
2549 TEST_F(MultiThreadedCookieMonsterTest
,
2550 ThreadCheckDeleteAllCreatedBetweenForHost
) {
2551 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2552 GURL
url_not_google("http://www.notgoogle.com");
2554 CookieOptions options
;
2555 Time now
= Time::Now();
2556 // ago1 < ago2 < ago3 < now.
2557 Time ago1
= now
- TimeDelta::FromDays(101);
2558 Time ago2
= now
- TimeDelta::FromDays(100);
2559 Time ago3
= now
- TimeDelta::FromDays(99);
2561 // These 3 cookies match the first deletion.
2562 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2563 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "C=D", options
));
2564 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "Y=Z", options
));
2566 // This cookie does not match host.
2567 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_not_google
, "E=F", options
));
2569 // This cookie does not match time range: [ago3, inf], for first deletion, but
2570 // matches for the second deletion.
2571 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "G=H", ago2
));
2573 // 1. First set of deletions.
2575 3, // Deletes A=B, C=D, Y=Z
2576 DeleteAllCreatedBetweenForHost(
2577 cm
.get(), ago3
, Time::Max(), url_google_
));
2579 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2580 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2582 // 2. Second set of deletions.
2583 base::Closure task
= base::Bind(
2584 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask
,
2585 base::Unretained(this),
2586 cm
, ago1
, Time(), url_google_
,
2588 RunOnOtherThread(task
);
2589 EXPECT_TRUE(callback
.did_run());
2590 EXPECT_EQ(2, callback
.result()); // Deletes A=B, G=H.
2593 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteCanonicalCookie
) {
2594 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2595 CookieOptions options
;
2596 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2597 CookieList cookies
= GetAllCookies(cm
.get());
2598 CookieList::iterator it
= cookies
.begin();
2599 EXPECT_TRUE(DeleteCanonicalCookie(cm
.get(), *it
));
2601 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2602 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2603 cookies
= GetAllCookies(cm
.get());
2604 it
= cookies
.begin();
2605 base::Closure task
= base::Bind(
2606 &net::MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask
,
2607 base::Unretained(this),
2608 cm
, *it
, &callback
);
2609 RunOnOtherThread(task
);
2610 EXPECT_TRUE(callback
.did_run());
2611 EXPECT_TRUE(callback
.result());
2614 TEST_F(CookieMonsterTest
, InvalidExpiryTime
) {
2615 std::string cookie_line
=
2616 std::string(kValidCookieLine
) + "; expires=Blarg arg arg";
2617 scoped_ptr
<CanonicalCookie
> cookie(
2618 CanonicalCookie::Create(url_google_
, cookie_line
, Time::Now(),
2620 ASSERT_FALSE(cookie
->IsPersistent());
2623 // Test that CookieMonster writes session cookies into the underlying
2624 // CookieStore if the "persist session cookies" option is on.
2625 TEST_F(CookieMonsterTest
, PersistSessionCookies
) {
2626 scoped_refptr
<MockPersistentCookieStore
> store(
2627 new MockPersistentCookieStore
);
2628 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2629 cm
->SetPersistSessionCookies(true);
2631 // All cookies set with SetCookie are session cookies.
2632 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2633 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
2635 // The cookie was written to the backing store.
2636 EXPECT_EQ(1u, store
->commands().size());
2637 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2638 EXPECT_EQ("A", store
->commands()[0].cookie
.Name());
2639 EXPECT_EQ("B", store
->commands()[0].cookie
.Value());
2641 // Modify the cookie.
2642 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=C"));
2643 EXPECT_EQ("A=C", GetCookies(cm
.get(), url_google_
));
2644 EXPECT_EQ(3u, store
->commands().size());
2645 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2646 EXPECT_EQ("A", store
->commands()[1].cookie
.Name());
2647 EXPECT_EQ("B", store
->commands()[1].cookie
.Value());
2648 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2649 EXPECT_EQ("A", store
->commands()[2].cookie
.Name());
2650 EXPECT_EQ("C", store
->commands()[2].cookie
.Value());
2652 // Delete the cookie.
2653 DeleteCookie(cm
.get(), url_google_
, "A");
2654 EXPECT_EQ("", GetCookies(cm
.get(), url_google_
));
2655 EXPECT_EQ(4u, store
->commands().size());
2656 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2657 EXPECT_EQ("A", store
->commands()[3].cookie
.Name());
2658 EXPECT_EQ("C", store
->commands()[3].cookie
.Value());
2661 // Test the commands sent to the persistent cookie store.
2662 TEST_F(CookieMonsterTest
, PersisentCookieStorageTest
) {
2663 scoped_refptr
<MockPersistentCookieStore
> store(
2664 new MockPersistentCookieStore
);
2665 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2668 EXPECT_TRUE(SetCookie(
2669 cm
.get(), url_google_
, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2670 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2671 ASSERT_EQ(1u, store
->commands().size());
2672 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2674 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B; max-age=0"));
2675 this->MatchCookieLines(std::string(), GetCookies(cm
.get(), url_google_
));
2676 ASSERT_EQ(2u, store
->commands().size());
2677 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2680 EXPECT_TRUE(SetCookie(
2681 cm
.get(), url_google_
, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2682 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2683 ASSERT_EQ(3u, store
->commands().size());
2684 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2686 EXPECT_TRUE(SetCookie(
2687 cm
.get(), url_google_
, "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
2688 this->MatchCookieLines("A=Foo", GetCookies(cm
.get(), url_google_
));
2689 ASSERT_EQ(5u, store
->commands().size());
2690 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2691 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[4].type
);
2693 // Create some non-persistent cookies and check that they don't go to the
2694 // persistent storage.
2695 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=Bar"));
2696 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm
.get(), url_google_
));
2697 EXPECT_EQ(5u, store
->commands().size());
2700 // Test to assure that cookies with control characters are purged appropriately.
2701 // See http://crbug.com/238041 for background.
2702 TEST_F(CookieMonsterTest
, ControlCharacterPurge
) {
2703 const Time
now1(Time::Now());
2704 const Time
now2(Time::Now() + TimeDelta::FromSeconds(1));
2705 const Time
now3(Time::Now() + TimeDelta::FromSeconds(2));
2706 const Time
later(now1
+ TimeDelta::FromDays(1));
2707 const GURL
url("http://host/path");
2708 const std::string
domain("host");
2709 const std::string
path("/path");
2711 scoped_refptr
<MockPersistentCookieStore
> store(
2712 new MockPersistentCookieStore
);
2714 std::vector
<CanonicalCookie
*> initial_cookies
;
2716 AddCookieToList(domain
,
2717 "foo=bar; path=" + path
,
2721 // We have to manually build this cookie because it contains a control
2722 // character, and our cookie line parser rejects control characters.
2723 CanonicalCookie
*cc
= new CanonicalCookie(url
, "baz", "\x05" "boo", domain
,
2724 path
, now2
, later
, now2
, false,
2725 false, COOKIE_PRIORITY_DEFAULT
);
2726 initial_cookies
.push_back(cc
);
2728 AddCookieToList(domain
,
2729 "hello=world; path=" + path
,
2733 // Inject our initial cookies into the mock PersistentCookieStore.
2734 store
->SetLoadExpectation(true, initial_cookies
);
2736 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2738 EXPECT_EQ("foo=bar; hello=world", GetCookies(cm
.get(), url
));
2741 class CookieMonsterNotificationTest
: public CookieMonsterTest
{
2743 CookieMonsterNotificationTest()
2744 : test_url_("http://www.google.com/foo"),
2745 store_(new MockPersistentCookieStore
),
2746 monster_(new CookieMonster(store_
.get(), NULL
)) {}
2748 ~CookieMonsterNotificationTest() override
{}
2750 CookieMonster
* monster() { return monster_
.get(); }
2753 const GURL test_url_
;
2756 scoped_refptr
<MockPersistentCookieStore
> store_
;
2757 scoped_refptr
<CookieMonster
> monster_
;
2760 void RecordCookieChanges(std::vector
<net::CanonicalCookie
>* out_cookies
,
2761 std::vector
<bool>* out_removes
,
2762 const net::CanonicalCookie
& cookie
,
2764 DCHECK(out_cookies
);
2765 out_cookies
->push_back(cookie
);
2767 out_removes
->push_back(removed
);
2770 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithNoCookie
) {
2771 std::vector
<net::CanonicalCookie
> cookies
;
2772 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2773 monster()->AddCallbackForCookie(test_url_
, "abc",
2774 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2775 base::MessageLoop::current()->RunUntilIdle();
2776 EXPECT_EQ(0U, cookies
.size());
2779 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithInitialCookie
) {
2780 std::vector
<net::CanonicalCookie
> cookies
;
2781 SetCookie(monster(), test_url_
, "abc=def");
2782 base::MessageLoop::current()->RunUntilIdle();
2783 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2784 monster()->AddCallbackForCookie(test_url_
, "abc",
2785 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2786 base::MessageLoop::current()->RunUntilIdle();
2787 EXPECT_EQ(0U, cookies
.size());
2790 TEST_F(CookieMonsterNotificationTest
, NotifyOnSet
) {
2791 std::vector
<net::CanonicalCookie
> cookies
;
2792 std::vector
<bool> removes
;
2793 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2794 monster()->AddCallbackForCookie(test_url_
, "abc",
2795 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2796 SetCookie(monster(), test_url_
, "abc=def");
2797 base::MessageLoop::current()->RunUntilIdle();
2798 EXPECT_EQ(1U, cookies
.size());
2799 EXPECT_EQ(1U, removes
.size());
2801 EXPECT_EQ("abc", cookies
[0].Name());
2802 EXPECT_EQ("def", cookies
[0].Value());
2803 EXPECT_FALSE(removes
[0]);
2806 TEST_F(CookieMonsterNotificationTest
, NotifyOnDelete
) {
2807 std::vector
<net::CanonicalCookie
> cookies
;
2808 std::vector
<bool> removes
;
2809 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2810 monster()->AddCallbackForCookie(test_url_
, "abc",
2811 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2812 SetCookie(monster(), test_url_
, "abc=def");
2813 base::MessageLoop::current()->RunUntilIdle();
2814 EXPECT_EQ(1U, cookies
.size());
2815 EXPECT_EQ(1U, removes
.size());
2817 DeleteCookie(monster(), test_url_
, "abc");
2818 base::MessageLoop::current()->RunUntilIdle();
2819 EXPECT_EQ(2U, cookies
.size());
2820 EXPECT_EQ(2U, removes
.size());
2822 EXPECT_EQ("abc", cookies
[1].Name());
2823 EXPECT_EQ("def", cookies
[1].Value());
2824 EXPECT_TRUE(removes
[1]);
2827 TEST_F(CookieMonsterNotificationTest
, NotifyOnUpdate
) {
2828 std::vector
<net::CanonicalCookie
> cookies
;
2829 std::vector
<bool> removes
;
2830 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2831 monster()->AddCallbackForCookie(test_url_
, "abc",
2832 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2833 SetCookie(monster(), test_url_
, "abc=def");
2834 base::MessageLoop::current()->RunUntilIdle();
2835 EXPECT_EQ(1U, cookies
.size());
2837 // Replacing an existing cookie is actually a two-phase delete + set
2838 // operation, so we get an extra notification.
2839 SetCookie(monster(), test_url_
, "abc=ghi");
2840 base::MessageLoop::current()->RunUntilIdle();
2842 EXPECT_EQ(3U, cookies
.size());
2843 EXPECT_EQ(3U, removes
.size());
2845 EXPECT_EQ("abc", cookies
[1].Name());
2846 EXPECT_EQ("def", cookies
[1].Value());
2847 EXPECT_TRUE(removes
[1]);
2849 EXPECT_EQ("abc", cookies
[2].Name());
2850 EXPECT_EQ("ghi", cookies
[2].Value());
2851 EXPECT_FALSE(removes
[2]);
2854 TEST_F(CookieMonsterNotificationTest
, MultipleNotifies
) {
2855 std::vector
<net::CanonicalCookie
> cookies0
;
2856 std::vector
<net::CanonicalCookie
> cookies1
;
2857 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
2858 monster()->AddCallbackForCookie(test_url_
, "abc",
2859 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
2860 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
2861 monster()->AddCallbackForCookie(test_url_
, "def",
2862 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
2863 SetCookie(monster(), test_url_
, "abc=def");
2864 base::MessageLoop::current()->RunUntilIdle();
2865 EXPECT_EQ(1U, cookies0
.size());
2866 EXPECT_EQ(0U, cookies1
.size());
2867 SetCookie(monster(), test_url_
, "def=abc");
2868 base::MessageLoop::current()->RunUntilIdle();
2869 EXPECT_EQ(1U, cookies0
.size());
2870 EXPECT_EQ(1U, cookies1
.size());
2873 TEST_F(CookieMonsterNotificationTest
, MultipleSameNotifies
) {
2874 std::vector
<net::CanonicalCookie
> cookies0
;
2875 std::vector
<net::CanonicalCookie
> cookies1
;
2876 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
2877 monster()->AddCallbackForCookie(test_url_
, "abc",
2878 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
2879 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
2880 monster()->AddCallbackForCookie(test_url_
, "abc",
2881 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
2882 SetCookie(monster(), test_url_
, "abc=def");
2883 base::MessageLoop::current()->RunUntilIdle();
2884 EXPECT_EQ(1U, cookies0
.size());
2885 EXPECT_EQ(1U, cookies0
.size());