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/location.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/scoped_vector.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/metrics/histogram.h"
19 #include "base/metrics/histogram_samples.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_piece.h"
23 #include "base/strings/string_split.h"
24 #include "base/strings/string_tokenizer.h"
25 #include "base/strings/stringprintf.h"
26 #include "base/test/histogram_tester.h"
27 #include "base/thread_task_runner_handle.h"
28 #include "base/threading/thread.h"
29 #include "base/time/time.h"
30 #include "net/cookies/canonical_cookie.h"
31 #include "net/cookies/cookie_constants.h"
32 #include "net/cookies/cookie_monster.h"
33 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
34 #include "net/cookies/cookie_util.h"
35 #include "net/cookies/parsed_cookie.h"
36 #include "testing/gmock/include/gmock/gmock.h"
37 #include "testing/gtest/include/gtest/gtest.h"
43 using base::TimeDelta
;
47 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and
48 // brethren) with this one, and remove the 'New' prefix.
49 class NewMockPersistentCookieStore
50 : public CookieMonster::PersistentCookieStore
{
52 MOCK_METHOD1(Load
, void(const LoadedCallback
& loaded_callback
));
53 MOCK_METHOD2(LoadCookiesForKey
,
54 void(const std::string
& key
,
55 const LoadedCallback
& loaded_callback
));
56 MOCK_METHOD1(AddCookie
, void(const CanonicalCookie
& cc
));
57 MOCK_METHOD1(UpdateCookieAccessTime
, void(const CanonicalCookie
& cc
));
58 MOCK_METHOD1(DeleteCookie
, void(const CanonicalCookie
& cc
));
59 virtual void Flush(const base::Closure
& callback
) {
60 if (!callback
.is_null())
61 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
63 MOCK_METHOD0(SetForceKeepSessionState
, void());
66 virtual ~NewMockPersistentCookieStore() {}
69 const char kTopLevelDomainPlus1
[] = "http://www.harvard.edu";
70 const char kTopLevelDomainPlus2
[] = "http://www.math.harvard.edu";
71 const char kTopLevelDomainPlus2Secure
[] = "https://www.math.harvard.edu";
72 const char kTopLevelDomainPlus3
[] = "http://www.bourbaki.math.harvard.edu";
73 const char kOtherDomain
[] = "http://www.mit.edu";
74 const char kUrlGoogleSpecific
[] = "http://www.gmail.google.izzle";
76 class GetCookieListCallback
: public CookieCallback
{
78 GetCookieListCallback() {}
79 explicit GetCookieListCallback(Thread
* run_in_thread
)
80 : CookieCallback(run_in_thread
) {}
82 void Run(const CookieList
& cookies
) {
87 const CookieList
& cookies() { return cookies_
; }
93 struct CookieMonsterTestTraits
{
94 static scoped_refptr
<CookieStore
> Create() {
95 return new CookieMonster(NULL
, NULL
);
98 static const bool is_cookie_monster
= true;
99 static const bool supports_http_only
= true;
100 static const bool supports_non_dotted_domains
= true;
101 static const bool supports_trailing_dots
= true;
102 static const bool filters_schemes
= true;
103 static const bool has_path_prefix_bug
= false;
104 static const int creation_time_granularity_in_ms
= 0;
107 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
109 CookieMonsterTestTraits
);
111 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
112 MultiThreadedCookieStoreTest
,
113 CookieMonsterTestTraits
);
115 class CookieMonsterTest
: public CookieStoreTest
<CookieMonsterTestTraits
> {
117 CookieList
GetAllCookies(CookieMonster
* cm
) {
119 GetCookieListCallback callback
;
120 cm
->GetAllCookiesAsync(
121 base::Bind(&GetCookieListCallback::Run
, base::Unretained(&callback
)));
123 EXPECT_TRUE(callback
.did_run());
124 return callback
.cookies();
127 CookieList
GetAllCookiesForURL(CookieMonster
* cm
, const GURL
& url
) {
129 GetCookieListCallback callback
;
130 cm
->GetAllCookiesForURLAsync(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(
144 base::Bind(&GetCookieListCallback::Run
, 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 bool first_party_only
,
160 CookiePriority priority
) {
162 ResultSavingCookieCallback
<bool> callback
;
163 cm
->SetCookieWithDetailsAsync(
164 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
165 first_party_only
, priority
,
166 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
167 base::Unretained(&callback
)));
169 EXPECT_TRUE(callback
.did_run());
170 return callback
.result();
173 bool SetAllCookies(CookieMonster
* cm
, const CookieList
& list
) {
175 ResultSavingCookieCallback
<bool> callback
;
176 cm
->SetAllCookiesAsync(list
,
177 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
178 base::Unretained(&callback
)));
180 EXPECT_TRUE(callback
.did_run());
181 return callback
.result();
184 int DeleteAll(CookieMonster
* cm
) {
186 ResultSavingCookieCallback
<int> callback
;
187 cm
->DeleteAllAsync(base::Bind(&ResultSavingCookieCallback
<int>::Run
,
188 base::Unretained(&callback
)));
190 EXPECT_TRUE(callback
.did_run());
191 return callback
.result();
194 int DeleteAllCreatedBetween(CookieMonster
* cm
,
195 const base::Time
& delete_begin
,
196 const base::Time
& delete_end
) {
198 ResultSavingCookieCallback
<int> callback
;
199 cm
->DeleteAllCreatedBetweenAsync(
200 delete_begin
, delete_end
,
201 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
202 base::Unretained(&callback
)));
204 EXPECT_TRUE(callback
.did_run());
205 return callback
.result();
208 int DeleteAllCreatedBetweenForHost(CookieMonster
* cm
,
209 const base::Time delete_begin
,
210 const base::Time delete_end
,
213 ResultSavingCookieCallback
<int> callback
;
214 cm
->DeleteAllCreatedBetweenForHostAsync(
215 delete_begin
, delete_end
, url
,
216 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
217 base::Unretained(&callback
)));
219 EXPECT_TRUE(callback
.did_run());
220 return callback
.result();
223 int DeleteAllForHost(CookieMonster
* cm
, const GURL
& url
) {
225 ResultSavingCookieCallback
<int> callback
;
226 cm
->DeleteAllForHostAsync(url
,
227 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
228 base::Unretained(&callback
)));
230 EXPECT_TRUE(callback
.did_run());
231 return callback
.result();
234 bool DeleteCanonicalCookie(CookieMonster
* cm
, const CanonicalCookie
& cookie
) {
236 ResultSavingCookieCallback
<bool> callback
;
237 cm
->DeleteCanonicalCookieAsync(
238 cookie
, base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
239 base::Unretained(&callback
)));
241 EXPECT_TRUE(callback
.did_run());
242 return callback
.result();
245 // Helper for DeleteAllForHost test; repopulates CM with same layout
247 void PopulateCmForDeleteAllForHost(scoped_refptr
<CookieMonster
> cm
) {
248 GURL
url_top_level_domain_plus_1(kTopLevelDomainPlus1
);
249 GURL
url_top_level_domain_plus_2(kTopLevelDomainPlus2
);
250 GURL
url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure
);
251 GURL
url_top_level_domain_plus_3(kTopLevelDomainPlus3
);
252 GURL
url_other(kOtherDomain
);
256 // Static population for probe:
257 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
258 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
259 // * http_only cookie (w.c.b.a)
260 // * first-party cookie (w.c.b.a)
261 // * Two secure cookies (.c.b.a, w.c.b.a)
262 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
263 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
266 EXPECT_TRUE(this->SetCookieWithDetails(
267 cm
.get(), url_top_level_domain_plus_1
, "dom_1", "X", ".harvard.edu",
268 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
269 EXPECT_TRUE(this->SetCookieWithDetails(
270 cm
.get(), url_top_level_domain_plus_2
, "dom_2", "X",
271 ".math.harvard.edu", "/", base::Time(), false, false, false,
272 COOKIE_PRIORITY_DEFAULT
));
273 EXPECT_TRUE(this->SetCookieWithDetails(
274 cm
.get(), url_top_level_domain_plus_3
, "dom_3", "X",
275 ".bourbaki.math.harvard.edu", "/", base::Time(), false, false, false,
276 COOKIE_PRIORITY_DEFAULT
));
279 EXPECT_TRUE(this->SetCookieWithDetails(
280 cm
.get(), url_top_level_domain_plus_1
, "host_1", "X", std::string(),
281 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
282 EXPECT_TRUE(this->SetCookieWithDetails(
283 cm
.get(), url_top_level_domain_plus_2
, "host_2", "X", std::string(),
284 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
285 EXPECT_TRUE(this->SetCookieWithDetails(
286 cm
.get(), url_top_level_domain_plus_3
, "host_3", "X", std::string(),
287 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
290 EXPECT_TRUE(this->SetCookieWithDetails(
291 cm
.get(), url_top_level_domain_plus_2
, "httpo_check", "x",
292 std::string(), "/", base::Time(), false, true, false,
293 COOKIE_PRIORITY_DEFAULT
));
295 // first-party cookie
296 EXPECT_TRUE(this->SetCookieWithDetails(
297 cm
.get(), url_top_level_domain_plus_2
, "firstp_check", "x",
298 std::string(), "/", base::Time(), false, false, true,
299 COOKIE_PRIORITY_DEFAULT
));
302 EXPECT_TRUE(this->SetCookieWithDetails(
303 cm
.get(), url_top_level_domain_plus_2_secure
, "sec_dom", "X",
304 ".math.harvard.edu", "/", base::Time(), true, false, false,
305 COOKIE_PRIORITY_DEFAULT
));
306 EXPECT_TRUE(this->SetCookieWithDetails(
307 cm
.get(), url_top_level_domain_plus_2_secure
, "sec_host", "X",
308 std::string(), "/", base::Time(), true, false, false,
309 COOKIE_PRIORITY_DEFAULT
));
311 // Domain path cookies
312 EXPECT_TRUE(this->SetCookieWithDetails(
313 cm
.get(), url_top_level_domain_plus_2
, "dom_path_1", "X",
314 ".math.harvard.edu", "/dir1", base::Time(), false, false, false,
315 COOKIE_PRIORITY_DEFAULT
));
316 EXPECT_TRUE(this->SetCookieWithDetails(
317 cm
.get(), url_top_level_domain_plus_2
, "dom_path_2", "X",
318 ".math.harvard.edu", "/dir1/dir2", base::Time(), false, false, false,
319 COOKIE_PRIORITY_DEFAULT
));
322 EXPECT_TRUE(this->SetCookieWithDetails(
323 cm
.get(), url_top_level_domain_plus_2
, "host_path_1", "X",
324 std::string(), "/dir1", base::Time(), false, false, false,
325 COOKIE_PRIORITY_DEFAULT
));
326 EXPECT_TRUE(this->SetCookieWithDetails(
327 cm
.get(), url_top_level_domain_plus_2
, "host_path_2", "X",
328 std::string(), "/dir1/dir2", base::Time(), false, false, false,
329 COOKIE_PRIORITY_DEFAULT
));
331 EXPECT_EQ(14U, this->GetAllCookies(cm
.get()).size());
334 Time
GetFirstCookieAccessDate(CookieMonster
* cm
) {
335 const CookieList
all_cookies(this->GetAllCookies(cm
));
336 return all_cookies
.front().LastAccessDate();
339 bool FindAndDeleteCookie(CookieMonster
* cm
,
340 const std::string
& domain
,
341 const std::string
& name
) {
342 CookieList cookies
= this->GetAllCookies(cm
);
343 for (CookieList::iterator it
= cookies
.begin(); it
!= cookies
.end(); ++it
)
344 if (it
->Domain() == domain
&& it
->Name() == name
)
345 return this->DeleteCanonicalCookie(cm
, *it
);
349 int CountInString(const std::string
& str
, char c
) {
350 return std::count(str
.begin(), str
.end(), c
);
353 void TestHostGarbageCollectHelper() {
354 int domain_max_cookies
= CookieMonster::kDomainMaxCookies
;
355 int domain_purge_cookies
= CookieMonster::kDomainPurgeCookies
;
356 const int more_than_enough_cookies
=
357 (domain_max_cookies
+ domain_purge_cookies
) * 2;
358 // Add a bunch of cookies on a single host, should purge them.
360 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
361 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
362 std::string cookie
= base::StringPrintf("a%03d=b", i
);
363 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie
));
364 std::string cookies
= this->GetCookies(cm
.get(), url_google_
);
365 // Make sure we find it in the cookies.
366 EXPECT_NE(cookies
.find(cookie
), std::string::npos
);
367 // Count the number of cookies.
368 EXPECT_LE(CountInString(cookies
, '='), domain_max_cookies
);
372 // Add a bunch of cookies on multiple hosts within a single eTLD.
373 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
374 // between them. We shouldn't go above kDomainMaxCookies for both together.
375 GURL
url_google_specific(kUrlGoogleSpecific
);
377 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
378 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
379 std::string cookie_general
= base::StringPrintf("a%03d=b", i
);
380 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie_general
));
381 std::string cookie_specific
= base::StringPrintf("c%03d=b", i
);
382 EXPECT_TRUE(SetCookie(cm
.get(), url_google_specific
, cookie_specific
));
383 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
384 EXPECT_NE(cookies_general
.find(cookie_general
), std::string::npos
);
385 std::string cookies_specific
=
386 this->GetCookies(cm
.get(), url_google_specific
);
387 EXPECT_NE(cookies_specific
.find(cookie_specific
), std::string::npos
);
388 EXPECT_LE((CountInString(cookies_general
, '=') +
389 CountInString(cookies_specific
, '=')),
392 // After all this, there should be at least
393 // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
394 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
395 std::string cookies_specific
=
396 this->GetCookies(cm
.get(), url_google_specific
);
397 int total_cookies
= (CountInString(cookies_general
, '=') +
398 CountInString(cookies_specific
, '='));
399 EXPECT_GE(total_cookies
, domain_max_cookies
- domain_purge_cookies
);
400 EXPECT_LE(total_cookies
, domain_max_cookies
);
404 CookiePriority
CharToPriority(char ch
) {
407 return COOKIE_PRIORITY_LOW
;
409 return COOKIE_PRIORITY_MEDIUM
;
411 return COOKIE_PRIORITY_HIGH
;
414 return COOKIE_PRIORITY_DEFAULT
;
417 // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
418 // priorities specified by |coded_priority_str|, and tests priority-aware
419 // domain cookie eviction.
420 // |coded_priority_str| specifies a run-length-encoded string of priorities.
421 // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
422 // from least- to most-recently accessed) insertion of 2 medium-priority
423 // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4
424 // high-priority cookies.
425 // Within each priority, only the least-accessed cookies should be evicted.
426 // Thus, to describe expected suriving cookies, it suffices to specify the
427 // expected population of surviving cookies per priority, i.e.,
428 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
429 void TestPriorityCookieCase(CookieMonster
* cm
,
430 const std::string
& coded_priority_str
,
431 size_t expected_low_count
,
432 size_t expected_medium_count
,
433 size_t expected_high_count
) {
435 int next_cookie_id
= 0;
436 std::vector
<CookiePriority
> priority_list
;
437 std::vector
<int> id_list
[3]; // Indexed by CookiePriority.
439 // Parse |coded_priority_str| and add cookies.
440 for (const std::string
& token
:
441 base::SplitString(coded_priority_str
, " ", base::TRIM_WHITESPACE
,
442 base::SPLIT_WANT_ALL
)) {
443 DCHECK(!token
.empty());
444 // Take last character as priority.
445 CookiePriority priority
= CharToPriority(token
[token
.length() - 1]);
446 std::string priority_str
= CookiePriorityToString(priority
);
447 // The rest of the string (possibly empty) specifies repetition.
449 if (!token
.empty()) {
450 bool result
= base::StringToInt(
451 base::StringPiece(token
.begin(), token
.end() - 1), &rep
);
454 for (; rep
> 0; --rep
, ++next_cookie_id
) {
455 std::string cookie
= base::StringPrintf(
456 "a%d=b;priority=%s", next_cookie_id
, priority_str
.c_str());
457 EXPECT_TRUE(SetCookie(cm
, url_google_
, cookie
));
458 priority_list
.push_back(priority
);
459 id_list
[priority
].push_back(next_cookie_id
);
463 int num_cookies
= static_cast<int>(priority_list
.size());
464 std::vector
<int> surviving_id_list
[3]; // Indexed by CookiePriority.
466 // Parse the list of cookies
467 std::string cookie_str
= this->GetCookies(cm
, url_google_
);
468 for (const std::string
& token
: base::SplitString(
469 cookie_str
, ";", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
)) {
470 // Assuming *it is "a#=b", so extract and parse "#" portion.
472 bool result
= base::StringToInt(
473 base::StringPiece(token
.begin() + 1, token
.end() - 2), &id
);
476 DCHECK_LT(id
, num_cookies
);
477 surviving_id_list
[priority_list
[id
]].push_back(id
);
480 // Validate each priority.
481 size_t expected_count
[3] = {
482 expected_low_count
, expected_medium_count
, expected_high_count
};
483 for (int i
= 0; i
< 3; ++i
) {
484 DCHECK_LE(surviving_id_list
[i
].size(), id_list
[i
].size());
485 EXPECT_EQ(expected_count
[i
], surviving_id_list
[i
].size());
486 // Verify that the remaining cookies are the most recent among those
487 // with the same priorities.
488 if (expected_count
[i
] == surviving_id_list
[i
].size()) {
489 std::sort(surviving_id_list
[i
].begin(), surviving_id_list
[i
].end());
490 EXPECT_TRUE(std::equal(surviving_id_list
[i
].begin(),
491 surviving_id_list
[i
].end(),
492 id_list
[i
].end() - expected_count
[i
]));
497 void TestPriorityAwareGarbageCollectHelper() {
498 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
499 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies
);
500 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies
-
501 CookieMonster::kDomainPurgeCookies
);
502 DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow
);
503 DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium
);
504 DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh
);
506 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
508 // Each test case adds 181 cookies, so 31 cookies are evicted.
509 // Cookie same priority, repeated for each priority.
510 TestPriorityCookieCase(cm
.get(), "181L", 150U, 0U, 0U);
511 TestPriorityCookieCase(cm
.get(), "181M", 0U, 150U, 0U);
512 TestPriorityCookieCase(cm
.get(), "181H", 0U, 0U, 150U);
514 // Pairwise scenarios.
515 // Round 1 => none; round2 => 31M; round 3 => none.
516 TestPriorityCookieCase(cm
.get(), "10H 171M", 0U, 140U, 10U);
517 // Round 1 => 10L; round2 => 21M; round 3 => none.
518 TestPriorityCookieCase(cm
.get(), "141M 40L", 30U, 120U, 0U);
519 // Round 1 => none; round2 => none; round 3 => 31H.
520 TestPriorityCookieCase(cm
.get(), "101H 80M", 0U, 80U, 70U);
522 // For {low, medium} priorities right on quota, different orders.
523 // Round 1 => 1L; round 2 => none, round3 => 30L.
524 TestPriorityCookieCase(cm
.get(), "31L 50M 100H", 0U, 50U, 100U);
525 // Round 1 => none; round 2 => 1M, round3 => 30M.
526 TestPriorityCookieCase(cm
.get(), "51M 100H 30L", 30U, 20U, 100U);
527 // Round 1 => none; round 2 => none; round3 => 31H.
528 TestPriorityCookieCase(cm
.get(), "101H 50M 30L", 30U, 50U, 70U);
530 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
531 TestPriorityCookieCase(cm
.get(), "81H 60M 40L", 30U, 50U, 70U);
533 // More complex scenarios.
534 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
535 TestPriorityCookieCase(cm
.get(), "21H 60M 40L 60H", 30U, 50U, 70U);
536 // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
537 TestPriorityCookieCase(cm
.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U,
539 // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
540 TestPriorityCookieCase(cm
.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U);
541 // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
542 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U);
543 // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
544 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U);
547 // Function for creating a CM with a number of cookies in it,
548 // no store (and hence no ability to affect access time).
549 CookieMonster
* CreateMonsterForGC(int num_cookies
) {
550 CookieMonster
* cm(new CookieMonster(NULL
, NULL
));
551 for (int i
= 0; i
< num_cookies
; i
++) {
552 SetCookie(cm
, GURL(base::StringPrintf("http://h%05d.izzle", i
)), "a=1");
557 bool IsCookieInList(const CanonicalCookie
& cookie
, const CookieList
& list
) {
558 for (CookieList::const_iterator it
= list
.begin(); it
!= list
.end(); ++it
) {
559 if (it
->Source() == cookie
.Source() && it
->Name() == cookie
.Name() &&
560 it
->Value() == cookie
.Value() && it
->Domain() == cookie
.Domain() &&
561 it
->Path() == cookie
.Path() &&
562 it
->CreationDate() == cookie
.CreationDate() &&
563 it
->ExpiryDate() == cookie
.ExpiryDate() &&
564 it
->LastAccessDate() == cookie
.LastAccessDate() &&
565 it
->IsSecure() == cookie
.IsSecure() &&
566 it
->IsHttpOnly() == cookie
.IsHttpOnly() &&
567 it
->Priority() == cookie
.Priority()) {
576 // TODO(erikwright): Replace the other callbacks and synchronous helper methods
577 // in this test suite with these Mocks.
578 template <typename T
, typename C
>
579 class MockCookieCallback
{
582 return base::Bind(&T::Invoke
, base::Unretained(static_cast<T
*>(this)));
586 class MockGetCookiesCallback
587 : public MockCookieCallback
<MockGetCookiesCallback
,
588 CookieStore::GetCookiesCallback
> {
590 MOCK_METHOD1(Invoke
, void(const std::string
& cookies
));
593 class MockSetCookiesCallback
594 : public MockCookieCallback
<MockSetCookiesCallback
,
595 CookieStore::SetCookiesCallback
> {
597 MOCK_METHOD1(Invoke
, void(bool success
));
600 class MockClosure
: public MockCookieCallback
<MockClosure
, base::Closure
> {
602 MOCK_METHOD0(Invoke
, void(void));
605 class MockGetCookieListCallback
606 : public MockCookieCallback
<MockGetCookieListCallback
,
607 CookieMonster::GetCookieListCallback
> {
609 MOCK_METHOD1(Invoke
, void(const CookieList
& cookies
));
612 class MockDeleteCallback
613 : public MockCookieCallback
<MockDeleteCallback
,
614 CookieMonster::DeleteCallback
> {
616 MOCK_METHOD1(Invoke
, void(int num_deleted
));
619 class MockDeleteCookieCallback
620 : public MockCookieCallback
<MockDeleteCookieCallback
,
621 CookieMonster::DeleteCookieCallback
> {
623 MOCK_METHOD1(Invoke
, void(bool success
));
626 struct CookiesInputInfo
{
628 const std::string name
;
629 const std::string value
;
630 const std::string domain
;
631 const std::string path
;
632 const base::Time expiration_time
;
635 bool first_party_only
;
636 CookiePriority priority
;
639 ACTION(QuitCurrentMessageLoop
) {
640 base::ThreadTaskRunnerHandle::Get()->PostTask(
641 FROM_HERE
, base::MessageLoop::QuitClosure());
644 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
645 // rename these, removing the 'Action' suffix.
646 ACTION_P4(DeleteCookieAction
, cookie_monster
, url
, name
, callback
) {
647 cookie_monster
->DeleteCookieAsync(url
, name
, callback
->AsCallback());
649 ACTION_P3(GetCookiesAction
, cookie_monster
, url
, callback
) {
650 cookie_monster
->GetCookiesWithOptionsAsync(url
, CookieOptions(),
651 callback
->AsCallback());
653 ACTION_P4(SetCookieAction
, cookie_monster
, url
, cookie_line
, callback
) {
654 cookie_monster
->SetCookieWithOptionsAsync(url
, cookie_line
, CookieOptions(),
655 callback
->AsCallback());
657 ACTION_P3(SetAllCookiesAction
, cookie_monster
, list
, callback
) {
658 cookie_monster
->SetAllCookiesAsync(list
, callback
->AsCallback());
660 ACTION_P4(DeleteAllCreatedBetweenAction
,
665 cookie_monster
->DeleteAllCreatedBetweenAsync(delete_begin
, delete_end
,
666 callback
->AsCallback());
668 ACTION_P3(SetCookieWithDetailsAction
, cookie_monster
, cc
, callback
) {
669 cookie_monster
->SetCookieWithDetailsAsync(
670 cc
.url
, cc
.name
, cc
.value
, cc
.domain
, cc
.path
, cc
.expiration_time
,
671 cc
.secure
, cc
.http_only
, cc
.first_party_only
, cc
.priority
,
672 callback
->AsCallback());
675 ACTION_P2(GetAllCookiesAction
, cookie_monster
, callback
) {
676 cookie_monster
->GetAllCookiesAsync(callback
->AsCallback());
679 ACTION_P3(DeleteAllForHostAction
, cookie_monster
, url
, callback
) {
680 cookie_monster
->DeleteAllForHostAsync(url
, callback
->AsCallback());
683 ACTION_P3(DeleteCanonicalCookieAction
, cookie_monster
, cookie
, callback
) {
684 cookie_monster
->DeleteCanonicalCookieAsync(cookie
, callback
->AsCallback());
687 ACTION_P2(DeleteAllAction
, cookie_monster
, callback
) {
688 cookie_monster
->DeleteAllAsync(callback
->AsCallback());
691 ACTION_P3(GetAllCookiesForUrlWithOptionsAction
, cookie_monster
, url
, callback
) {
692 cookie_monster
->GetAllCookiesForURLWithOptionsAsync(url
, CookieOptions(),
693 callback
->AsCallback());
696 ACTION_P3(GetAllCookiesForUrlAction
, cookie_monster
, url
, callback
) {
697 cookie_monster
->GetAllCookiesForURLAsync(url
, callback
->AsCallback());
700 ACTION_P(PushCallbackAction
, callback_vector
) {
701 callback_vector
->push(arg1
);
704 ACTION_P2(DeleteSessionCookiesAction
, cookie_monster
, callback
) {
705 cookie_monster
->DeleteSessionCookiesAsync(callback
->AsCallback());
710 // This test suite verifies the task deferral behaviour of the CookieMonster.
711 // Specifically, for each asynchronous method, verify that:
712 // 1. invoking it on an uninitialized cookie store causes the store to begin
713 // chain-loading its backing data or loading data for a specific domain key
715 // 2. The initial invocation does not complete until the loading completes.
716 // 3. Invocations after the loading has completed complete immediately.
717 class DeferredCookieTaskTest
: public CookieMonsterTest
{
719 DeferredCookieTaskTest() {
720 persistent_store_
= new NewMockPersistentCookieStore();
721 cookie_monster_
= new CookieMonster(persistent_store_
.get(), NULL
);
724 // Defines a cookie to be returned from PersistentCookieStore::Load
725 void DeclareLoadedCookie(const std::string
& key
,
726 const std::string
& cookie_line
,
727 const base::Time
& creation_time
) {
728 AddCookieToList(key
, cookie_line
, creation_time
, &loaded_cookies_
);
731 // Runs the message loop, waiting until PersistentCookieStore::Load is called.
732 // Call CompleteLoadingAndWait to cause the load to complete.
733 void WaitForLoadCall() {
736 // Verify that PeristentStore::Load was called.
737 testing::Mock::VerifyAndClear(persistent_store_
.get());
740 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
741 // and PersistentCookieStore::Load completion callback and waits
742 // until the message loop is quit.
743 void CompleteLoadingAndWait() {
744 while (!loaded_for_key_callbacks_
.empty()) {
745 loaded_for_key_callbacks_
.front().Run(loaded_cookies_
);
746 loaded_cookies_
.clear();
747 loaded_for_key_callbacks_
.pop();
750 loaded_callback_
.Run(loaded_cookies_
);
754 // Performs the provided action, expecting it to cause a call to
755 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call
757 void BeginWith(testing::Action
<void(void)> action
) {
758 EXPECT_CALL(*this, Begin()).WillOnce(action
);
763 void BeginWithForDomainKey(std::string key
,
764 testing::Action
<void(void)> action
) {
765 EXPECT_CALL(*this, Begin()).WillOnce(action
);
767 ExpectLoadForKeyCall(key
, false);
771 // Declares an expectation that PersistentCookieStore::Load will be called,
772 // saving the provided callback and sending a quit to the message loop.
773 void ExpectLoadCall() {
774 EXPECT_CALL(*persistent_store_
.get(), Load(testing::_
))
775 .WillOnce(testing::DoAll(testing::SaveArg
<0>(&loaded_callback_
),
776 QuitCurrentMessageLoop()));
779 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
780 // will be called, saving the provided callback and sending a quit to the
782 void ExpectLoadForKeyCall(std::string key
, bool quit_queue
) {
784 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
786 testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_
),
787 QuitCurrentMessageLoop()));
789 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
790 .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_
));
793 // Invokes the initial action.
794 MOCK_METHOD0(Begin
, void(void));
796 // Returns the CookieMonster instance under test.
797 CookieMonster
& cookie_monster() { return *cookie_monster_
.get(); }
800 // Declares that mock expectations in this test suite are strictly ordered.
801 testing::InSequence in_sequence_
;
802 // Holds cookies to be returned from PersistentCookieStore::Load or
803 // PersistentCookieStore::LoadCookiesForKey.
804 std::vector
<CanonicalCookie
*> loaded_cookies_
;
805 // Stores the callback passed from the CookieMonster to the
806 // PersistentCookieStore::Load
807 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_
;
808 // Stores the callback passed from the CookieMonster to the
809 // PersistentCookieStore::LoadCookiesForKey
810 std::queue
<CookieMonster::PersistentCookieStore::LoadedCallback
>
811 loaded_for_key_callbacks_
;
813 // Stores the CookieMonster under test.
814 scoped_refptr
<CookieMonster
> cookie_monster_
;
815 // Stores the mock PersistentCookieStore.
816 scoped_refptr
<NewMockPersistentCookieStore
> persistent_store_
;
819 TEST_F(DeferredCookieTaskTest
, DeferredGetCookies
) {
820 DeclareLoadedCookie("www.google.izzle",
821 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
822 Time::Now() + TimeDelta::FromDays(3));
824 MockGetCookiesCallback get_cookies_callback
;
826 BeginWithForDomainKey(
828 GetCookiesAction(&cookie_monster(), url_google_
, &get_cookies_callback
));
832 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
833 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_
,
834 &get_cookies_callback
));
835 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
836 .WillOnce(QuitCurrentMessageLoop());
838 CompleteLoadingAndWait();
841 TEST_F(DeferredCookieTaskTest
, DeferredSetCookie
) {
842 MockSetCookiesCallback set_cookies_callback
;
844 BeginWithForDomainKey("google.izzle",
845 SetCookieAction(&cookie_monster(), url_google_
, "A=B",
846 &set_cookies_callback
));
850 EXPECT_CALL(set_cookies_callback
, Invoke(true))
851 .WillOnce(SetCookieAction(&cookie_monster(), url_google_
, "X=Y",
852 &set_cookies_callback
));
853 EXPECT_CALL(set_cookies_callback
, Invoke(true))
854 .WillOnce(QuitCurrentMessageLoop());
856 CompleteLoadingAndWait();
859 TEST_F(DeferredCookieTaskTest
, DeferredSetAllCookies
) {
860 MockSetCookiesCallback set_cookies_callback
;
862 list
.push_back(CanonicalCookie(url_google_
, "A", "B", "google.izzle", "/",
863 base::Time::Now(), base::Time(), base::Time(),
864 false, true, false, COOKIE_PRIORITY_DEFAULT
));
865 list
.push_back(CanonicalCookie(url_google_
, "C", "D", "google.izzle", "/",
866 base::Time::Now(), base::Time(), base::Time(),
867 false, true, false, COOKIE_PRIORITY_DEFAULT
));
870 SetAllCookiesAction(&cookie_monster(), list
, &set_cookies_callback
));
874 EXPECT_CALL(set_cookies_callback
, Invoke(true))
876 SetAllCookiesAction(&cookie_monster(), list
, &set_cookies_callback
));
877 EXPECT_CALL(set_cookies_callback
, Invoke(true))
878 .WillOnce(QuitCurrentMessageLoop());
880 CompleteLoadingAndWait();
883 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCookie
) {
884 MockClosure delete_cookie_callback
;
886 BeginWithForDomainKey("google.izzle",
887 DeleteCookieAction(&cookie_monster(), url_google_
, "A",
888 &delete_cookie_callback
));
892 EXPECT_CALL(delete_cookie_callback
, Invoke())
893 .WillOnce(DeleteCookieAction(&cookie_monster(), url_google_
, "X",
894 &delete_cookie_callback
));
895 EXPECT_CALL(delete_cookie_callback
, Invoke())
896 .WillOnce(QuitCurrentMessageLoop());
898 CompleteLoadingAndWait();
901 TEST_F(DeferredCookieTaskTest
, DeferredSetCookieWithDetails
) {
902 MockSetCookiesCallback set_cookies_callback
;
904 CookiesInputInfo cookie_info
= {url_google_foo_
,
913 COOKIE_PRIORITY_DEFAULT
};
914 BeginWithForDomainKey(
915 "google.izzle", SetCookieWithDetailsAction(&cookie_monster(), cookie_info
,
916 &set_cookies_callback
));
920 CookiesInputInfo cookie_info_exp
= {url_google_foo_
,
929 COOKIE_PRIORITY_DEFAULT
};
930 EXPECT_CALL(set_cookies_callback
, Invoke(true))
931 .WillOnce(SetCookieWithDetailsAction(&cookie_monster(), cookie_info_exp
,
932 &set_cookies_callback
));
933 EXPECT_CALL(set_cookies_callback
, Invoke(true))
934 .WillOnce(QuitCurrentMessageLoop());
936 CompleteLoadingAndWait();
939 TEST_F(DeferredCookieTaskTest
, DeferredGetAllCookies
) {
940 DeclareLoadedCookie("www.google.izzle",
941 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
942 Time::Now() + TimeDelta::FromDays(3));
944 MockGetCookieListCallback get_cookie_list_callback
;
946 BeginWith(GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback
));
950 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
952 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback
));
953 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
954 .WillOnce(QuitCurrentMessageLoop());
956 CompleteLoadingAndWait();
959 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlCookies
) {
960 DeclareLoadedCookie("www.google.izzle",
961 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
962 Time::Now() + TimeDelta::FromDays(3));
964 MockGetCookieListCallback get_cookie_list_callback
;
966 BeginWithForDomainKey(
967 "google.izzle", GetAllCookiesForUrlAction(&cookie_monster(), url_google_
,
968 &get_cookie_list_callback
));
972 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
973 .WillOnce(GetAllCookiesForUrlAction(&cookie_monster(), url_google_
,
974 &get_cookie_list_callback
));
975 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
976 .WillOnce(QuitCurrentMessageLoop());
978 CompleteLoadingAndWait();
981 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlWithOptionsCookies
) {
982 DeclareLoadedCookie("www.google.izzle",
983 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
984 Time::Now() + TimeDelta::FromDays(3));
986 MockGetCookieListCallback get_cookie_list_callback
;
988 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
989 &cookie_monster(), url_google_
,
990 &get_cookie_list_callback
));
994 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
995 .WillOnce(GetAllCookiesForUrlWithOptionsAction(
996 &cookie_monster(), url_google_
, &get_cookie_list_callback
));
997 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
998 .WillOnce(QuitCurrentMessageLoop());
1000 CompleteLoadingAndWait();
1003 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCookies
) {
1004 MockDeleteCallback delete_callback
;
1006 BeginWith(DeleteAllAction(&cookie_monster(), &delete_callback
));
1010 EXPECT_CALL(delete_callback
, Invoke(false))
1011 .WillOnce(DeleteAllAction(&cookie_monster(), &delete_callback
));
1012 EXPECT_CALL(delete_callback
, Invoke(false))
1013 .WillOnce(QuitCurrentMessageLoop());
1015 CompleteLoadingAndWait();
1018 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCreatedBetweenCookies
) {
1019 MockDeleteCallback delete_callback
;
1021 BeginWith(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
1022 base::Time::Now(), &delete_callback
));
1026 EXPECT_CALL(delete_callback
, Invoke(false))
1027 .WillOnce(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
1030 EXPECT_CALL(delete_callback
, Invoke(false))
1031 .WillOnce(QuitCurrentMessageLoop());
1033 CompleteLoadingAndWait();
1036 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllForHostCookies
) {
1037 MockDeleteCallback delete_callback
;
1039 BeginWithForDomainKey(
1041 DeleteAllForHostAction(&cookie_monster(), url_google_
, &delete_callback
));
1045 EXPECT_CALL(delete_callback
, Invoke(false))
1046 .WillOnce(DeleteAllForHostAction(&cookie_monster(), url_google_
,
1048 EXPECT_CALL(delete_callback
, Invoke(false))
1049 .WillOnce(QuitCurrentMessageLoop());
1051 CompleteLoadingAndWait();
1054 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCanonicalCookie
) {
1055 std::vector
<CanonicalCookie
*> cookies
;
1056 CanonicalCookie cookie
=
1057 BuildCanonicalCookie("www.google.com", "X=1; path=/", base::Time::Now());
1059 MockDeleteCookieCallback delete_cookie_callback
;
1061 BeginWith(DeleteCanonicalCookieAction(&cookie_monster(), cookie
,
1062 &delete_cookie_callback
));
1066 EXPECT_CALL(delete_cookie_callback
, Invoke(false))
1067 .WillOnce(DeleteCanonicalCookieAction(&cookie_monster(), cookie
,
1068 &delete_cookie_callback
));
1069 EXPECT_CALL(delete_cookie_callback
, Invoke(false))
1070 .WillOnce(QuitCurrentMessageLoop());
1072 CompleteLoadingAndWait();
1075 TEST_F(DeferredCookieTaskTest
, DeferredDeleteSessionCookies
) {
1076 MockDeleteCallback delete_callback
;
1078 BeginWith(DeleteSessionCookiesAction(&cookie_monster(), &delete_callback
));
1082 EXPECT_CALL(delete_callback
, Invoke(false))
1084 DeleteSessionCookiesAction(&cookie_monster(), &delete_callback
));
1085 EXPECT_CALL(delete_callback
, Invoke(false))
1086 .WillOnce(QuitCurrentMessageLoop());
1088 CompleteLoadingAndWait();
1091 // Verify that a series of queued tasks are executed in order upon loading of
1092 // the backing store and that new tasks received while the queued tasks are
1093 // being dispatched go to the end of the queue.
1094 TEST_F(DeferredCookieTaskTest
, DeferredTaskOrder
) {
1095 DeclareLoadedCookie("www.google.izzle",
1096 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1097 Time::Now() + TimeDelta::FromDays(3));
1099 MockGetCookiesCallback get_cookies_callback
;
1100 MockSetCookiesCallback set_cookies_callback
;
1101 MockGetCookiesCallback get_cookies_callback_deferred
;
1103 EXPECT_CALL(*this, Begin())
1104 .WillOnce(testing::DoAll(GetCookiesAction(&cookie_monster(), url_google_
,
1105 &get_cookies_callback
),
1106 SetCookieAction(&cookie_monster(), url_google_
,
1107 "A=B", &set_cookies_callback
)));
1109 ExpectLoadForKeyCall("google.izzle", false);
1113 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
1114 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_
,
1115 &get_cookies_callback_deferred
));
1116 EXPECT_CALL(set_cookies_callback
, Invoke(true));
1117 EXPECT_CALL(get_cookies_callback_deferred
, Invoke("A=B; X=1"))
1118 .WillOnce(QuitCurrentMessageLoop());
1120 CompleteLoadingAndWait();
1123 TEST_F(CookieMonsterTest
, TestCookieDeleteAll
) {
1124 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1125 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1126 CookieOptions options
;
1127 options
.set_include_httponly();
1129 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
1130 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1133 SetCookieWithOptions(cm
.get(), url_google_
, "C=D; httponly", options
));
1134 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1136 EXPECT_EQ(2, DeleteAll(cm
.get()));
1137 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1138 EXPECT_EQ(0u, store
->commands().size());
1140 // Create a persistent cookie.
1141 EXPECT_TRUE(SetCookie(
1142 cm
.get(), url_google_
,
1143 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1144 ASSERT_EQ(1u, store
->commands().size());
1145 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1147 EXPECT_EQ(1, DeleteAll(cm
.get())); // sync_to_store = true.
1148 ASSERT_EQ(2u, store
->commands().size());
1149 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1151 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1154 TEST_F(CookieMonsterTest
, TestCookieDeleteAllCreatedBetweenTimestamps
) {
1155 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1156 Time now
= Time::Now();
1158 // Nothing has been added so nothing should be deleted.
1159 EXPECT_EQ(0, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99),
1162 // Create 3 cookies with creation date of today, yesterday and the day before.
1163 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-0=Now", now
));
1164 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-1=Yesterday",
1165 now
- TimeDelta::FromDays(1)));
1166 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-2=DayBefore",
1167 now
- TimeDelta::FromDays(2)));
1168 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-3=ThreeDays",
1169 now
- TimeDelta::FromDays(3)));
1170 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-7=LastWeek",
1171 now
- TimeDelta::FromDays(7)));
1173 // Try to delete threedays and the daybefore.
1174 EXPECT_EQ(2, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(3),
1175 now
- TimeDelta::FromDays(1)));
1177 // Try to delete yesterday, also make sure that delete_end is not
1180 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(2), now
));
1182 // Make sure the delete_begin is inclusive.
1184 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(7), now
));
1186 // Delete the last (now) item.
1187 EXPECT_EQ(1, DeleteAllCreatedBetween(cm
.get(), Time(), Time()));
1189 // Really make sure everything is gone.
1190 EXPECT_EQ(0, DeleteAll(cm
.get()));
1193 static const int kAccessDelayMs
= kLastAccessThresholdMilliseconds
+ 20;
1195 TEST_F(CookieMonsterTest
, TestLastAccess
) {
1196 scoped_refptr
<CookieMonster
> cm(
1197 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1199 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1200 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1202 // Reading the cookie again immediately shouldn't update the access date,
1203 // since we're inside the threshold.
1204 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1205 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1207 // Reading after a short wait should update the access date.
1208 base::PlatformThread::Sleep(
1209 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1210 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1211 EXPECT_FALSE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1214 TEST_F(CookieMonsterTest
, TestHostGarbageCollection
) {
1215 TestHostGarbageCollectHelper();
1218 TEST_F(CookieMonsterTest
, TestPriorityAwareGarbageCollection
) {
1219 TestPriorityAwareGarbageCollectHelper();
1222 TEST_F(CookieMonsterTest
, TestDeleteSingleCookie
) {
1223 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1225 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1226 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1227 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1228 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1230 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1231 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1233 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1234 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1237 TEST_F(CookieMonsterTest
, SetCookieableSchemes
) {
1238 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1239 scoped_refptr
<CookieMonster
> cm_foo(new CookieMonster(NULL
, NULL
));
1241 // Only cm_foo should allow foo:// cookies.
1242 const char* const kSchemes
[] = {"foo"};
1243 cm_foo
->SetCookieableSchemes(kSchemes
, 1);
1245 GURL
foo_url("foo://host/path");
1246 GURL
http_url("http://host/path");
1248 EXPECT_TRUE(SetCookie(cm
.get(), http_url
, "x=1"));
1249 EXPECT_FALSE(SetCookie(cm
.get(), foo_url
, "x=1"));
1250 EXPECT_TRUE(SetCookie(cm_foo
.get(), foo_url
, "x=1"));
1251 EXPECT_FALSE(SetCookie(cm_foo
.get(), http_url
, "x=1"));
1254 TEST_F(CookieMonsterTest
, GetAllCookiesForURL
) {
1255 scoped_refptr
<CookieMonster
> cm(
1256 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1258 // Create an httponly cookie.
1259 CookieOptions options
;
1260 options
.set_include_httponly();
1263 SetCookieWithOptions(cm
.get(), url_google_
, "A=B; httponly", options
));
1264 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
,
1265 "C=D; domain=.google.izzle", options
));
1266 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_secure_
,
1267 "E=F; domain=.google.izzle; secure",
1270 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1272 base::PlatformThread::Sleep(
1273 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1275 // Check cookies for url.
1276 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
1277 CookieList::iterator it
= cookies
.begin();
1279 ASSERT_TRUE(it
!= cookies
.end());
1280 EXPECT_EQ("www.google.izzle", it
->Domain());
1281 EXPECT_EQ("A", it
->Name());
1283 ASSERT_TRUE(++it
!= cookies
.end());
1284 EXPECT_EQ(".google.izzle", it
->Domain());
1285 EXPECT_EQ("C", it
->Name());
1287 ASSERT_TRUE(++it
== cookies
.end());
1289 // Check cookies for url excluding http-only cookies.
1291 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, CookieOptions());
1292 it
= cookies
.begin();
1294 ASSERT_TRUE(it
!= cookies
.end());
1295 EXPECT_EQ(".google.izzle", it
->Domain());
1296 EXPECT_EQ("C", it
->Name());
1298 ASSERT_TRUE(++it
== cookies
.end());
1300 // Test secure cookies.
1301 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1302 it
= cookies
.begin();
1304 ASSERT_TRUE(it
!= cookies
.end());
1305 EXPECT_EQ("www.google.izzle", it
->Domain());
1306 EXPECT_EQ("A", it
->Name());
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());
1313 EXPECT_EQ(".google.izzle", it
->Domain());
1314 EXPECT_EQ("E", it
->Name());
1316 ASSERT_TRUE(++it
== cookies
.end());
1318 // Reading after a short wait should not update the access date.
1319 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1322 TEST_F(CookieMonsterTest
, GetAllCookiesForURLPathMatching
) {
1323 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1324 CookieOptions options
;
1326 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_foo_
, "A=B; path=/foo;",
1328 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_bar_
, "C=D; path=/bar;",
1330 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "E=F;", options
));
1332 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1333 CookieList::iterator it
= cookies
.begin();
1335 ASSERT_TRUE(it
!= cookies
.end());
1336 EXPECT_EQ("A", it
->Name());
1337 EXPECT_EQ("/foo", it
->Path());
1339 ASSERT_TRUE(++it
!= cookies
.end());
1340 EXPECT_EQ("E", it
->Name());
1341 EXPECT_EQ("/", it
->Path());
1343 ASSERT_TRUE(++it
== cookies
.end());
1345 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1346 it
= cookies
.begin();
1348 ASSERT_TRUE(it
!= cookies
.end());
1349 EXPECT_EQ("C", it
->Name());
1350 EXPECT_EQ("/bar", it
->Path());
1352 ASSERT_TRUE(++it
!= cookies
.end());
1353 EXPECT_EQ("E", it
->Name());
1354 EXPECT_EQ("/", it
->Path());
1356 ASSERT_TRUE(++it
== cookies
.end());
1359 TEST_F(CookieMonsterTest
, DeleteCookieByName
) {
1360 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1362 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A1; path=/"));
1363 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A2; path=/foo"));
1364 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A3; path=/bar"));
1365 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B1; path=/"));
1366 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B2; path=/foo"));
1367 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B3; path=/bar"));
1369 DeleteCookie(cm
.get(), GURL(std::string(kUrlGoogle
) + "/foo/bar"), "A");
1371 CookieList cookies
= GetAllCookies(cm
.get());
1372 size_t expected_size
= 4;
1373 EXPECT_EQ(expected_size
, cookies
.size());
1374 for (CookieList::iterator it
= cookies
.begin(); it
!= cookies
.end(); ++it
) {
1375 EXPECT_NE("A1", it
->Value());
1376 EXPECT_NE("A2", it
->Value());
1380 TEST_F(CookieMonsterTest
, ImportCookiesFromCookieMonster
) {
1381 scoped_refptr
<CookieMonster
> cm_1(new CookieMonster(NULL
, NULL
));
1382 CookieOptions options
;
1384 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_foo_
,
1385 "A1=B; path=/foo;", options
));
1386 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_bar_
,
1387 "A2=D; path=/bar;", options
));
1388 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_
, "A3=F;", options
));
1390 CookieList cookies_1
= GetAllCookies(cm_1
.get());
1391 scoped_refptr
<CookieMonster
> cm_2(new CookieMonster(NULL
, NULL
));
1392 ASSERT_TRUE(cm_2
->ImportCookies(cookies_1
));
1393 CookieList cookies_2
= GetAllCookies(cm_2
.get());
1395 size_t expected_size
= 3;
1396 EXPECT_EQ(expected_size
, cookies_2
.size());
1398 CookieList::iterator it
= cookies_2
.begin();
1400 ASSERT_TRUE(it
!= cookies_2
.end());
1401 EXPECT_EQ("A1", it
->Name());
1402 EXPECT_EQ("/foo", it
->Path());
1404 ASSERT_TRUE(++it
!= cookies_2
.end());
1405 EXPECT_EQ("A2", it
->Name());
1406 EXPECT_EQ("/bar", it
->Path());
1408 ASSERT_TRUE(++it
!= cookies_2
.end());
1409 EXPECT_EQ("A3", it
->Name());
1410 EXPECT_EQ("/", it
->Path());
1413 // Tests importing from a persistent cookie store that contains duplicate
1414 // equivalent cookies. This situation should be handled by removing the
1415 // duplicate cookie (both from the in-memory cache, and from the backing store).
1417 // This is a regression test for: http://crbug.com/17855.
1418 TEST_F(CookieMonsterTest
, DontImportDuplicateCookies
) {
1419 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1421 // We will fill some initial cookies into the PersistentCookieStore,
1422 // to simulate a database with 4 duplicates. Note that we need to
1423 // be careful not to have any duplicate creation times at all (as it's a
1424 // violation of a CookieMonster invariant) even if Time::Now() doesn't
1425 // move between calls.
1426 std::vector
<CanonicalCookie
*> initial_cookies
;
1428 // Insert 4 cookies with name "X" on path "/", with varying creation
1429 // dates. We expect only the most recent one to be preserved following
1432 AddCookieToList("www.google.com",
1433 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1434 Time::Now() + TimeDelta::FromDays(3), &initial_cookies
);
1436 AddCookieToList("www.google.com",
1437 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1438 Time::Now() + TimeDelta::FromDays(1), &initial_cookies
);
1440 // ===> This one is the WINNER (biggest creation time). <====
1441 AddCookieToList("www.google.com",
1442 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1443 Time::Now() + TimeDelta::FromDays(4), &initial_cookies
);
1445 AddCookieToList("www.google.com",
1446 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1447 Time::Now(), &initial_cookies
);
1449 // Insert 2 cookies with name "X" on path "/2", with varying creation
1450 // dates. We expect only the most recent one to be preserved the import.
1452 // ===> This one is the WINNER (biggest creation time). <====
1453 AddCookieToList("www.google.com",
1454 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1455 Time::Now() + TimeDelta::FromDays(9), &initial_cookies
);
1457 AddCookieToList("www.google.com",
1458 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1459 Time::Now() + TimeDelta::FromDays(2), &initial_cookies
);
1461 // Insert 1 cookie with name "Y" on path "/".
1462 AddCookieToList("www.google.com",
1463 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1464 Time::Now() + TimeDelta::FromDays(10), &initial_cookies
);
1466 // Inject our initial cookies into the mock PersistentCookieStore.
1467 store
->SetLoadExpectation(true, initial_cookies
);
1469 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1471 // Verify that duplicates were not imported for path "/".
1472 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1473 EXPECT_EQ("X=3; Y=a", GetCookies(cm
.get(), GURL("http://www.google.com/")));
1475 // Verify that same-named cookie on a different path ("/x2") didn't get
1477 EXPECT_EQ("X=a1; X=3; Y=a",
1478 GetCookies(cm
.get(), GURL("http://www.google.com/2/x")));
1480 // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1481 ASSERT_EQ(4u, store
->commands().size());
1482 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[0].type
);
1483 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1484 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[2].type
);
1485 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
1488 // Tests importing from a persistent cookie store that contains cookies
1489 // with duplicate creation times. This situation should be handled by
1490 // dropping the cookies before insertion/visibility to user.
1492 // This is a regression test for: http://crbug.com/43188.
1493 TEST_F(CookieMonsterTest
, DontImportDuplicateCreationTimes
) {
1494 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1496 Time
now(Time::Now());
1497 Time
earlier(now
- TimeDelta::FromDays(1));
1499 // Insert 8 cookies, four with the current time as creation times, and
1500 // four with the earlier time as creation times. We should only get
1501 // two cookies remaining, but which two (other than that there should
1502 // be one from each set) will be random.
1503 std::vector
<CanonicalCookie
*> initial_cookies
;
1504 AddCookieToList("www.google.com", "X=1; path=/", now
, &initial_cookies
);
1505 AddCookieToList("www.google.com", "X=2; path=/", now
, &initial_cookies
);
1506 AddCookieToList("www.google.com", "X=3; path=/", now
, &initial_cookies
);
1507 AddCookieToList("www.google.com", "X=4; path=/", now
, &initial_cookies
);
1509 AddCookieToList("www.google.com", "Y=1; path=/", earlier
, &initial_cookies
);
1510 AddCookieToList("www.google.com", "Y=2; path=/", earlier
, &initial_cookies
);
1511 AddCookieToList("www.google.com", "Y=3; path=/", earlier
, &initial_cookies
);
1512 AddCookieToList("www.google.com", "Y=4; path=/", earlier
, &initial_cookies
);
1514 // Inject our initial cookies into the mock PersistentCookieStore.
1515 store
->SetLoadExpectation(true, initial_cookies
);
1517 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1519 CookieList
list(GetAllCookies(cm
.get()));
1520 EXPECT_EQ(2U, list
.size());
1521 // Confirm that we have one of each.
1522 std::string
name1(list
[0].Name());
1523 std::string
name2(list
[1].Name());
1524 EXPECT_TRUE(name1
== "X" || name2
== "X");
1525 EXPECT_TRUE(name1
== "Y" || name2
== "Y");
1526 EXPECT_NE(name1
, name2
);
1529 TEST_F(CookieMonsterTest
, CookieMonsterDelegate
) {
1530 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1531 scoped_refptr
<MockCookieMonsterDelegate
> delegate(
1532 new MockCookieMonsterDelegate
);
1533 scoped_refptr
<CookieMonster
> cm(
1534 new CookieMonster(store
.get(), delegate
.get()));
1536 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1537 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1538 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1539 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1540 ASSERT_EQ(3u, delegate
->changes().size());
1541 EXPECT_FALSE(delegate
->changes()[0].second
);
1542 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1543 EXPECT_EQ("A", delegate
->changes()[0].first
.Name());
1544 EXPECT_EQ("B", delegate
->changes()[0].first
.Value());
1545 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1546 EXPECT_FALSE(delegate
->changes()[1].second
);
1547 EXPECT_EQ("C", delegate
->changes()[1].first
.Name());
1548 EXPECT_EQ("D", delegate
->changes()[1].first
.Value());
1549 EXPECT_EQ(url_google_
.host(), delegate
->changes()[2].first
.Domain());
1550 EXPECT_FALSE(delegate
->changes()[2].second
);
1551 EXPECT_EQ("E", delegate
->changes()[2].first
.Name());
1552 EXPECT_EQ("F", delegate
->changes()[2].first
.Value());
1555 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1556 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1557 ASSERT_EQ(1u, delegate
->changes().size());
1558 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1559 EXPECT_TRUE(delegate
->changes()[0].second
);
1560 EXPECT_EQ("C", delegate
->changes()[0].first
.Name());
1561 EXPECT_EQ("D", delegate
->changes()[0].first
.Value());
1564 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1565 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1566 EXPECT_EQ(0u, delegate
->changes().size());
1568 // Insert a cookie "a" for path "/path1"
1569 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
1570 "a=val1; path=/path1; "
1571 "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1572 ASSERT_EQ(1u, store
->commands().size());
1573 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1574 ASSERT_EQ(1u, delegate
->changes().size());
1575 EXPECT_FALSE(delegate
->changes()[0].second
);
1576 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1577 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1578 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1581 // Insert a cookie "a" for path "/path1", that is httponly. This should
1582 // overwrite the non-http-only version.
1583 CookieOptions allow_httponly
;
1584 allow_httponly
.set_include_httponly();
1585 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
,
1586 "a=val2; path=/path1; httponly; "
1587 "expires=Mon, 18-Apr-22 22:50:14 GMT",
1589 ASSERT_EQ(3u, store
->commands().size());
1590 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1591 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
1592 ASSERT_EQ(2u, delegate
->changes().size());
1593 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1594 EXPECT_TRUE(delegate
->changes()[0].second
);
1595 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1596 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1597 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1598 EXPECT_FALSE(delegate
->changes()[1].second
);
1599 EXPECT_EQ("a", delegate
->changes()[1].first
.Name());
1600 EXPECT_EQ("val2", delegate
->changes()[1].first
.Value());
1604 TEST_F(CookieMonsterTest
, SetCookieWithDetails
) {
1605 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1607 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A", "B",
1608 std::string(), "/foo", base::Time(), false,
1609 false, false, COOKIE_PRIORITY_DEFAULT
));
1610 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_bar_
, "C", "D",
1611 "google.izzle", "/bar", base::Time(), false,
1612 true, false, COOKIE_PRIORITY_DEFAULT
));
1613 EXPECT_TRUE(SetCookieWithDetails(
1614 cm
.get(), url_google_
, "E", "F", std::string(), std::string(),
1615 base::Time(), true, false, false, COOKIE_PRIORITY_DEFAULT
));
1617 // Test that malformed attributes fail to set the cookie.
1618 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, " A", "B",
1619 std::string(), "/foo", base::Time(), false,
1620 false, false, COOKIE_PRIORITY_DEFAULT
));
1621 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A;", "B",
1622 std::string(), "/foo", base::Time(), false,
1623 false, false, COOKIE_PRIORITY_DEFAULT
));
1624 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A=", "B",
1625 std::string(), "/foo", base::Time(), false,
1626 false, false, COOKIE_PRIORITY_DEFAULT
));
1627 EXPECT_FALSE(SetCookieWithDetails(
1628 cm
.get(), url_google_foo_
, "A", "B", "google.ozzzzzzle", "foo",
1629 base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
1630 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A=", "B",
1631 std::string(), "foo", base::Time(), false,
1632 false, false, COOKIE_PRIORITY_DEFAULT
));
1634 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1635 CookieList::iterator it
= cookies
.begin();
1637 ASSERT_TRUE(it
!= cookies
.end());
1638 EXPECT_EQ("A", it
->Name());
1639 EXPECT_EQ("B", it
->Value());
1640 EXPECT_EQ("www.google.izzle", it
->Domain());
1641 EXPECT_EQ("/foo", it
->Path());
1642 EXPECT_FALSE(it
->IsPersistent());
1643 EXPECT_FALSE(it
->IsSecure());
1644 EXPECT_FALSE(it
->IsHttpOnly());
1646 ASSERT_TRUE(++it
== cookies
.end());
1648 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1649 it
= cookies
.begin();
1651 ASSERT_TRUE(it
!= cookies
.end());
1652 EXPECT_EQ("C", it
->Name());
1653 EXPECT_EQ("D", it
->Value());
1654 EXPECT_EQ(".google.izzle", it
->Domain());
1655 EXPECT_EQ("/bar", it
->Path());
1656 EXPECT_FALSE(it
->IsSecure());
1657 EXPECT_TRUE(it
->IsHttpOnly());
1659 ASSERT_TRUE(++it
== cookies
.end());
1661 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1662 it
= cookies
.begin();
1664 ASSERT_TRUE(it
!= cookies
.end());
1665 EXPECT_EQ("E", it
->Name());
1666 EXPECT_EQ("F", it
->Value());
1667 EXPECT_EQ("/", it
->Path());
1668 EXPECT_EQ("www.google.izzle", it
->Domain());
1669 EXPECT_TRUE(it
->IsSecure());
1670 EXPECT_FALSE(it
->IsHttpOnly());
1672 ASSERT_TRUE(++it
== cookies
.end());
1675 TEST_F(CookieMonsterTest
, DeleteAllForHost
) {
1676 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1679 // * Non-secure URL, mid-level (http://w.c.b.a)
1680 // * Secure URL, mid-level (https://w.c.b.a)
1681 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1682 // All three tests should nuke only the midlevel host cookie,
1683 // the http_only cookie, the host secure cookie, and the two host
1684 // path cookies. http_only, secure, and paths are ignored by
1685 // this call, and domain cookies arent touched.
1686 PopulateCmForDeleteAllForHost(cm
);
1687 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1688 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1689 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1690 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1691 EXPECT_EQ("dom_1=X; host_1=X",
1692 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1694 "dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1695 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1696 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1697 std::string("/dir1/dir2/xxx"))));
1699 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2
)));
1700 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1702 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1703 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1704 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1705 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1706 EXPECT_EQ("dom_1=X; host_1=X",
1707 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1708 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1709 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1710 std::string("/dir1/dir2/xxx"))));
1712 PopulateCmForDeleteAllForHost(cm
);
1713 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1714 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1716 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1717 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1718 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1719 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1720 EXPECT_EQ("dom_1=X; host_1=X",
1721 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1722 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1723 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1724 std::string("/dir1/dir2/xxx"))));
1726 PopulateCmForDeleteAllForHost(cm
);
1727 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1728 std::string("/dir1/xxx"))));
1729 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1731 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1732 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1733 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1734 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1735 EXPECT_EQ("dom_1=X; host_1=X",
1736 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1737 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1738 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1739 std::string("/dir1/dir2/xxx"))));
1742 TEST_F(CookieMonsterTest
, UniqueCreationTime
) {
1743 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1744 CookieOptions options
;
1746 // Add in three cookies through every public interface to the
1747 // CookieMonster and confirm that none of them have duplicate
1750 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1751 // are not included as they aren't going to be public for very much
1754 // SetCookie, SetCookieWithOptions, SetCookieWithDetails
1756 SetCookie(cm
.get(), url_google_
, "SetCookie1=A");
1757 SetCookie(cm
.get(), url_google_
, "SetCookie2=A");
1758 SetCookie(cm
.get(), url_google_
, "SetCookie3=A");
1760 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions1=A",
1762 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions2=A",
1764 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions3=A",
1767 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails1", "A",
1768 ".google.com", "/", Time(), false, false, false,
1769 COOKIE_PRIORITY_DEFAULT
);
1770 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails2", "A",
1771 ".google.com", "/", Time(), false, false, false,
1772 COOKIE_PRIORITY_DEFAULT
);
1773 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails3", "A",
1774 ".google.com", "/", Time(), false, false, false,
1775 COOKIE_PRIORITY_DEFAULT
);
1778 CookieList
cookie_list(GetAllCookies(cm
.get()));
1779 typedef std::map
<int64
, CanonicalCookie
> TimeCookieMap
;
1780 TimeCookieMap check_map
;
1781 for (CookieList::const_iterator it
= cookie_list
.begin();
1782 it
!= cookie_list
.end(); it
++) {
1783 const int64 creation_date
= it
->CreationDate().ToInternalValue();
1784 TimeCookieMap::const_iterator
existing_cookie_it(
1785 check_map
.find(creation_date
));
1786 EXPECT_TRUE(existing_cookie_it
== check_map
.end())
1787 << "Cookie " << it
->Name() << " has same creation date ("
1788 << it
->CreationDate().ToInternalValue()
1789 << ") as previously entered cookie "
1790 << existing_cookie_it
->second
.Name();
1792 if (existing_cookie_it
== check_map
.end()) {
1794 TimeCookieMap::value_type(it
->CreationDate().ToInternalValue(), *it
));
1799 // Mainly a test of GetEffectiveDomain, or more specifically, of the
1800 // expected behavior of GetEffectiveDomain within the CookieMonster.
1801 TEST_F(CookieMonsterTest
, GetKey
) {
1802 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1804 // This test is really only interesting if GetKey() actually does something.
1805 EXPECT_EQ("google.com", cm
->GetKey("www.google.com"));
1806 EXPECT_EQ("google.izzie", cm
->GetKey("www.google.izzie"));
1807 EXPECT_EQ("google.izzie", cm
->GetKey(".google.izzie"));
1808 EXPECT_EQ("bbc.co.uk", cm
->GetKey("bbc.co.uk"));
1809 EXPECT_EQ("bbc.co.uk", cm
->GetKey("a.b.c.d.bbc.co.uk"));
1810 EXPECT_EQ("apple.com", cm
->GetKey("a.b.c.d.apple.com"));
1811 EXPECT_EQ("apple.izzie", cm
->GetKey("a.b.c.d.apple.izzie"));
1813 // Cases where the effective domain is null, so we use the host
1815 EXPECT_EQ("co.uk", cm
->GetKey("co.uk"));
1816 const std::string
extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1817 EXPECT_EQ(extension_name
, cm
->GetKey(extension_name
));
1818 EXPECT_EQ("com", cm
->GetKey("com"));
1819 EXPECT_EQ("hostalias", cm
->GetKey("hostalias"));
1820 EXPECT_EQ("localhost", cm
->GetKey("localhost"));
1823 // Test that cookies transfer from/to the backing store correctly.
1824 TEST_F(CookieMonsterTest
, BackingStoreCommunication
) {
1825 // Store details for cookies transforming through the backing store interface.
1827 base::Time
current(base::Time::Now());
1828 scoped_refptr
<MockSimplePersistentCookieStore
> store(
1829 new MockSimplePersistentCookieStore
);
1830 base::Time new_access_time
;
1831 base::Time
expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1833 const CookiesInputInfo input_info
[] = {
1834 {GURL("http://a.b.google.com"),
1843 COOKIE_PRIORITY_DEFAULT
},
1844 {GURL("https://www.google.com"),
1848 "/path/from/cookie",
1849 expires
+ TimeDelta::FromSeconds(10),
1853 COOKIE_PRIORITY_DEFAULT
},
1854 {GURL("https://google.com"),
1858 "/another/path/to/cookie",
1859 base::Time::Now() + base::TimeDelta::FromSeconds(100),
1863 COOKIE_PRIORITY_DEFAULT
}};
1864 const int INPUT_DELETE
= 1;
1866 // Create new cookies and flush them to the store.
1868 scoped_refptr
<CookieMonster
> cmout(new CookieMonster(store
.get(), NULL
));
1869 for (const CookiesInputInfo
* p
= input_info
;
1870 p
< &input_info
[arraysize(input_info
)]; p
++) {
1871 EXPECT_TRUE(SetCookieWithDetails(cmout
.get(), p
->url
, p
->name
, p
->value
,
1872 p
->domain
, p
->path
, p
->expiration_time
,
1873 p
->secure
, p
->http_only
,
1874 p
->first_party_only
, p
->priority
));
1876 GURL
del_url(input_info
[INPUT_DELETE
]
1877 .url
.Resolve(input_info
[INPUT_DELETE
].path
)
1879 DeleteCookie(cmout
.get(), del_url
, input_info
[INPUT_DELETE
].name
);
1882 // Create a new cookie monster and make sure that everything is correct
1884 scoped_refptr
<CookieMonster
> cmin(new CookieMonster(store
.get(), NULL
));
1885 CookieList
cookies(GetAllCookies(cmin
.get()));
1886 ASSERT_EQ(2u, cookies
.size());
1887 // Ordering is path length, then creation time. So second cookie
1888 // will come first, and we need to swap them.
1889 std::swap(cookies
[0], cookies
[1]);
1890 for (int output_index
= 0; output_index
< 2; output_index
++) {
1891 int input_index
= output_index
* 2;
1892 const CookiesInputInfo
* input
= &input_info
[input_index
];
1893 const CanonicalCookie
* output
= &cookies
[output_index
];
1895 EXPECT_EQ(input
->name
, output
->Name());
1896 EXPECT_EQ(input
->value
, output
->Value());
1897 EXPECT_EQ(input
->url
.host(), output
->Domain());
1898 EXPECT_EQ(input
->path
, output
->Path());
1899 EXPECT_LE(current
.ToInternalValue(),
1900 output
->CreationDate().ToInternalValue());
1901 EXPECT_EQ(input
->secure
, output
->IsSecure());
1902 EXPECT_EQ(input
->http_only
, output
->IsHttpOnly());
1903 EXPECT_EQ(input
->first_party_only
, output
->IsFirstPartyOnly());
1904 EXPECT_TRUE(output
->IsPersistent());
1905 EXPECT_EQ(input
->expiration_time
.ToInternalValue(),
1906 output
->ExpiryDate().ToInternalValue());
1911 TEST_F(CookieMonsterTest
, CookieListOrdering
) {
1912 // Put a random set of cookies into a monster and make sure
1913 // they're returned in the right order.
1914 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1916 SetCookie(cm
.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1"));
1917 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1918 "d=1; domain=b.a.google.com"));
1919 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1920 "a=4; domain=b.a.google.com"));
1921 EXPECT_TRUE(SetCookie(cm
.get(),
1922 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
1923 "e=1; domain=c.b.a.google.com"));
1924 EXPECT_TRUE(SetCookie(cm
.get(),
1925 GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1"));
1926 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://news.bbc.co.uk/midpath/x.html"),
1930 CookieList
cookies(GetAllCookiesForURL(
1931 cm
.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
1932 ASSERT_EQ(5u, cookies
.size());
1933 EXPECT_EQ("d", cookies
[i
++].Name());
1934 EXPECT_EQ("a", cookies
[i
++].Name());
1935 EXPECT_EQ("e", cookies
[i
++].Name());
1936 EXPECT_EQ("b", cookies
[i
++].Name());
1937 EXPECT_EQ("c", cookies
[i
++].Name());
1942 CookieList
cookies(GetAllCookies(cm
.get()));
1943 ASSERT_EQ(6u, cookies
.size());
1944 EXPECT_EQ("d", cookies
[i
++].Name());
1945 EXPECT_EQ("a", cookies
[i
++].Name());
1946 EXPECT_EQ("e", cookies
[i
++].Name());
1947 EXPECT_EQ("g", cookies
[i
++].Name());
1948 EXPECT_EQ("b", cookies
[i
++].Name());
1949 EXPECT_EQ("c", cookies
[i
++].Name());
1953 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
1954 // are somewhat complementary twins. This test is probing for whether
1955 // garbage collection always happens when it should (i.e. that we actually
1956 // get rid of cookies when we should). The perftest is probing for
1957 // whether garbage collection happens when it shouldn't. See comments
1958 // before that test for more details.
1960 // Disabled on Windows, see crbug.com/126095
1962 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers
1964 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers
1967 TEST_F(CookieMonsterTest
, MAYBE_GarbageCollectionTriggers
) {
1968 // First we check to make sure that a whole lot of recent cookies
1969 // doesn't get rid of anything after garbage collection is checked for.
1971 scoped_refptr
<CookieMonster
> cm(
1972 CreateMonsterForGC(CookieMonster::kMaxCookies
* 2));
1973 EXPECT_EQ(CookieMonster::kMaxCookies
* 2, GetAllCookies(cm
.get()).size());
1974 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
1975 EXPECT_EQ(CookieMonster::kMaxCookies
* 2 + 1,
1976 GetAllCookies(cm
.get()).size());
1979 // Now we explore a series of relationships between cookie last access
1980 // time and size of store to make sure we only get rid of cookies when
1981 // we really should.
1982 const struct TestCase
{
1984 size_t num_old_cookies
;
1985 size_t expected_initial_cookies
;
1986 // Indexed by ExpiryAndKeyScheme
1987 size_t expected_cookies_after_set
;
1989 {// A whole lot of recent cookies; gc shouldn't happen.
1990 CookieMonster::kMaxCookies
* 2,
1992 CookieMonster::kMaxCookies
* 2,
1993 CookieMonster::kMaxCookies
* 2 + 1},
1994 {// Some old cookies, but still overflowing max.
1995 CookieMonster::kMaxCookies
* 2,
1996 CookieMonster::kMaxCookies
/ 2,
1997 CookieMonster::kMaxCookies
* 2,
1998 CookieMonster::kMaxCookies
* 2 - CookieMonster::kMaxCookies
/ 2 + 1},
1999 {// Old cookies enough to bring us right down to our purge line.
2000 CookieMonster::kMaxCookies
* 2,
2001 CookieMonster::kMaxCookies
+ CookieMonster::kPurgeCookies
+ 1,
2002 CookieMonster::kMaxCookies
* 2,
2003 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
},
2004 {// Old cookies enough to bring below our purge line (which we
2006 CookieMonster::kMaxCookies
* 2,
2007 CookieMonster::kMaxCookies
* 3 / 2,
2008 CookieMonster::kMaxCookies
* 2,
2009 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
}};
2011 for (int ci
= 0; ci
< static_cast<int>(arraysize(test_cases
)); ++ci
) {
2012 const TestCase
* test_case
= &test_cases
[ci
];
2013 scoped_refptr
<CookieMonster
> cm(CreateMonsterFromStoreForGC(
2014 test_case
->num_cookies
, test_case
->num_old_cookies
,
2015 CookieMonster::kSafeFromGlobalPurgeDays
* 2));
2016 EXPECT_EQ(test_case
->expected_initial_cookies
,
2017 GetAllCookies(cm
.get()).size())
2018 << "For test case " << ci
;
2020 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
2021 EXPECT_EQ(test_case
->expected_cookies_after_set
,
2022 GetAllCookies(cm
.get()).size())
2023 << "For test case " << ci
;
2027 // This test checks that keep expired cookies flag is working.
2028 TEST_F(CookieMonsterTest
, KeepExpiredCookies
) {
2029 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2030 cm
->SetKeepExpiredCookies();
2031 CookieOptions options
;
2033 // Set a persistent cookie.
2034 ASSERT_TRUE(SetCookieWithOptions(
2035 cm
.get(), url_google_
,
2036 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2039 // Get the canonical cookie.
2040 CookieList cookie_list
= GetAllCookies(cm
.get());
2041 ASSERT_EQ(1U, cookie_list
.size());
2043 // Use a past expiry date to delete the cookie.
2044 ASSERT_TRUE(SetCookieWithOptions(
2045 cm
.get(), url_google_
,
2046 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2049 // Check that the cookie with the past expiry date is still there.
2050 // GetAllCookies() also triggers garbage collection.
2051 cookie_list
= GetAllCookies(cm
.get());
2052 ASSERT_EQ(1U, cookie_list
.size());
2053 ASSERT_TRUE(cookie_list
[0].IsExpired(Time::Now()));
2058 // Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2059 class FlushablePersistentStore
: public CookieMonster::PersistentCookieStore
{
2061 FlushablePersistentStore() : flush_count_(0) {}
2063 void Load(const LoadedCallback
& loaded_callback
) override
{
2064 std::vector
<CanonicalCookie
*> out_cookies
;
2065 base::ThreadTaskRunnerHandle::Get()->PostTask(
2067 base::Bind(&LoadedCallbackTask::Run
,
2068 new LoadedCallbackTask(loaded_callback
, out_cookies
)));
2071 void LoadCookiesForKey(const std::string
& key
,
2072 const LoadedCallback
& loaded_callback
) override
{
2073 Load(loaded_callback
);
2076 void AddCookie(const CanonicalCookie
&) override
{}
2077 void UpdateCookieAccessTime(const CanonicalCookie
&) override
{}
2078 void DeleteCookie(const CanonicalCookie
&) override
{}
2079 void SetForceKeepSessionState() override
{}
2081 void Flush(const base::Closure
& callback
) override
{
2083 if (!callback
.is_null())
2087 int flush_count() { return flush_count_
; }
2090 ~FlushablePersistentStore() override
{}
2092 volatile int flush_count_
;
2095 // Counts the number of times Callback() has been run.
2096 class CallbackCounter
: public base::RefCountedThreadSafe
<CallbackCounter
> {
2098 CallbackCounter() : callback_count_(0) {}
2100 void Callback() { ++callback_count_
; }
2102 int callback_count() { return callback_count_
; }
2105 friend class base::RefCountedThreadSafe
<CallbackCounter
>;
2106 ~CallbackCounter() {}
2108 volatile int callback_count_
;
2113 // Test that FlushStore() is forwarded to the store and callbacks are posted.
2114 TEST_F(CookieMonsterTest
, FlushStore
) {
2115 scoped_refptr
<CallbackCounter
> counter(new CallbackCounter());
2116 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2117 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2119 ASSERT_EQ(0, store
->flush_count());
2120 ASSERT_EQ(0, counter
->callback_count());
2122 // Before initialization, FlushStore() should just run the callback.
2123 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2124 base::MessageLoop::current()->RunUntilIdle();
2126 ASSERT_EQ(0, store
->flush_count());
2127 ASSERT_EQ(1, counter
->callback_count());
2129 // NULL callback is safe.
2130 cm
->FlushStore(base::Closure());
2131 base::MessageLoop::current()->RunUntilIdle();
2133 ASSERT_EQ(0, store
->flush_count());
2134 ASSERT_EQ(1, counter
->callback_count());
2136 // After initialization, FlushStore() should delegate to the store.
2137 GetAllCookies(cm
.get()); // Force init.
2138 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2139 base::MessageLoop::current()->RunUntilIdle();
2141 ASSERT_EQ(1, store
->flush_count());
2142 ASSERT_EQ(2, counter
->callback_count());
2144 // NULL callback is still safe.
2145 cm
->FlushStore(base::Closure());
2146 base::MessageLoop::current()->RunUntilIdle();
2148 ASSERT_EQ(2, store
->flush_count());
2149 ASSERT_EQ(2, counter
->callback_count());
2151 // If there's no backing store, FlushStore() is always a safe no-op.
2152 cm
= new CookieMonster(NULL
, NULL
);
2153 GetAllCookies(cm
.get()); // Force init.
2154 cm
->FlushStore(base::Closure());
2155 base::MessageLoop::current()->RunUntilIdle();
2157 ASSERT_EQ(2, counter
->callback_count());
2159 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2160 base::MessageLoop::current()->RunUntilIdle();
2162 ASSERT_EQ(3, counter
->callback_count());
2165 TEST_F(CookieMonsterTest
, SetAllCookies
) {
2166 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2167 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2168 cm
->SetPersistSessionCookies(true);
2170 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "U=V; path=/"));
2171 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "W=X; path=/foo"));
2172 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "Y=Z; path=/"));
2175 list
.push_back(CanonicalCookie(url_google_
, "A", "B", url_google_
.host(), "/",
2176 base::Time::Now(), base::Time(), base::Time(),
2177 false, false, false, COOKIE_PRIORITY_DEFAULT
));
2178 list
.push_back(CanonicalCookie(url_google_
, "W", "X", url_google_
.host(),
2179 "/bar", base::Time::Now(), base::Time(),
2180 base::Time(), false, false, false,
2181 COOKIE_PRIORITY_DEFAULT
));
2182 list
.push_back(CanonicalCookie(url_google_
, "Y", "Z", url_google_
.host(), "/",
2183 base::Time::Now(), base::Time(), base::Time(),
2184 false, false, false, COOKIE_PRIORITY_DEFAULT
));
2186 // SetAllCookies must not flush.
2187 ASSERT_EQ(0, store
->flush_count());
2188 EXPECT_TRUE(SetAllCookies(cm
.get(), list
));
2189 EXPECT_EQ(0, store
->flush_count());
2191 CookieList cookies
= GetAllCookies(cm
.get());
2192 size_t expected_size
= 3; // "A", "W" and "Y". "U" is gone.
2193 EXPECT_EQ(expected_size
, cookies
.size());
2194 CookieList::iterator it
= cookies
.begin();
2196 ASSERT_TRUE(it
!= cookies
.end());
2197 EXPECT_EQ("W", it
->Name());
2198 EXPECT_EQ("X", it
->Value());
2199 EXPECT_EQ("/bar", it
->Path()); // The path has been updated.
2201 ASSERT_TRUE(++it
!= cookies
.end());
2202 EXPECT_EQ("A", it
->Name());
2203 EXPECT_EQ("B", it
->Value());
2205 ASSERT_TRUE(++it
!= cookies
.end());
2206 EXPECT_EQ("Y", it
->Name());
2207 EXPECT_EQ("Z", it
->Value());
2210 TEST_F(CookieMonsterTest
, ComputeCookieDiff
) {
2211 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2213 base::Time now
= base::Time::Now();
2214 base::Time creation_time
= now
- base::TimeDelta::FromSeconds(1);
2216 CanonicalCookie
cookie1(url_google_
, "A", "B", url_google_
.host(), "/",
2217 creation_time
, base::Time(), base::Time(), false,
2218 false, false, COOKIE_PRIORITY_DEFAULT
);
2219 CanonicalCookie
cookie2(url_google_
, "C", "D", url_google_
.host(), "/",
2220 creation_time
, base::Time(), base::Time(), false,
2221 false, false, COOKIE_PRIORITY_DEFAULT
);
2222 CanonicalCookie
cookie3(url_google_
, "E", "F", url_google_
.host(), "/",
2223 creation_time
, base::Time(), base::Time(), false,
2224 false, false, COOKIE_PRIORITY_DEFAULT
);
2225 CanonicalCookie
cookie4(url_google_
, "G", "H", url_google_
.host(), "/",
2226 creation_time
, base::Time(), base::Time(), false,
2227 false, false, COOKIE_PRIORITY_DEFAULT
);
2228 CanonicalCookie
cookie4_with_new_value(
2229 url_google_
, "G", "iamnew", url_google_
.host(), "/", creation_time
,
2230 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2231 CanonicalCookie
cookie5(url_google_
, "I", "J", url_google_
.host(), "/",
2232 creation_time
, base::Time(), base::Time(), false,
2233 false, false, COOKIE_PRIORITY_DEFAULT
);
2234 CanonicalCookie
cookie5_with_new_creation_time(
2235 url_google_
, "I", "J", url_google_
.host(), "/", now
, base::Time(),
2236 base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2237 CanonicalCookie
cookie6(url_google_
, "K", "L", url_google_
.host(), "/foo",
2238 creation_time
, base::Time(), base::Time(), false,
2239 false, false, COOKIE_PRIORITY_DEFAULT
);
2240 CanonicalCookie
cookie6_with_new_path(
2241 url_google_
, "K", "L", url_google_
.host(), "/bar", creation_time
,
2242 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2243 CanonicalCookie
cookie7(url_google_
, "M", "N", url_google_
.host(), "/foo",
2244 creation_time
, base::Time(), base::Time(), false,
2245 false, false, COOKIE_PRIORITY_DEFAULT
);
2246 CanonicalCookie
cookie7_with_new_path(
2247 url_google_
, "M", "N", url_google_
.host(), "/bar", creation_time
,
2248 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2250 CookieList old_cookies
;
2251 old_cookies
.push_back(cookie1
);
2252 old_cookies
.push_back(cookie2
);
2253 old_cookies
.push_back(cookie4
);
2254 old_cookies
.push_back(cookie5
);
2255 old_cookies
.push_back(cookie6
);
2256 old_cookies
.push_back(cookie7
);
2258 CookieList new_cookies
;
2259 new_cookies
.push_back(cookie1
);
2260 new_cookies
.push_back(cookie3
);
2261 new_cookies
.push_back(cookie4_with_new_value
);
2262 new_cookies
.push_back(cookie5_with_new_creation_time
);
2263 new_cookies
.push_back(cookie6_with_new_path
);
2264 new_cookies
.push_back(cookie7
);
2265 new_cookies
.push_back(cookie7_with_new_path
);
2267 CookieList cookies_to_add
;
2268 CookieList cookies_to_delete
;
2270 cm
->ComputeCookieDiff(&old_cookies
, &new_cookies
, &cookies_to_add
,
2271 &cookies_to_delete
);
2273 // |cookie1| has not changed.
2274 EXPECT_FALSE(IsCookieInList(cookie1
, cookies_to_add
));
2275 EXPECT_FALSE(IsCookieInList(cookie1
, cookies_to_delete
));
2277 // |cookie2| has been deleted.
2278 EXPECT_FALSE(IsCookieInList(cookie2
, cookies_to_add
));
2279 EXPECT_TRUE(IsCookieInList(cookie2
, cookies_to_delete
));
2281 // |cookie3| has been added.
2282 EXPECT_TRUE(IsCookieInList(cookie3
, cookies_to_add
));
2283 EXPECT_FALSE(IsCookieInList(cookie3
, cookies_to_delete
));
2285 // |cookie4| has a new value: new cookie overrides the old one (which does not
2286 // need to be explicitly removed).
2287 EXPECT_FALSE(IsCookieInList(cookie4
, cookies_to_add
));
2288 EXPECT_FALSE(IsCookieInList(cookie4
, cookies_to_delete
));
2289 EXPECT_TRUE(IsCookieInList(cookie4_with_new_value
, cookies_to_add
));
2290 EXPECT_FALSE(IsCookieInList(cookie4_with_new_value
, cookies_to_delete
));
2292 // |cookie5| has a new creation time: new cookie overrides the old one (which
2293 // does not need to be explicitly removed).
2294 EXPECT_FALSE(IsCookieInList(cookie5
, cookies_to_add
));
2295 EXPECT_FALSE(IsCookieInList(cookie5
, cookies_to_delete
));
2296 EXPECT_TRUE(IsCookieInList(cookie5_with_new_creation_time
, cookies_to_add
));
2298 IsCookieInList(cookie5_with_new_creation_time
, cookies_to_delete
));
2300 // |cookie6| has a new path: the new cookie does not overrides the old one,
2301 // which needs to be explicitly removed.
2302 EXPECT_FALSE(IsCookieInList(cookie6
, cookies_to_add
));
2303 EXPECT_TRUE(IsCookieInList(cookie6
, cookies_to_delete
));
2304 EXPECT_TRUE(IsCookieInList(cookie6_with_new_path
, cookies_to_add
));
2305 EXPECT_FALSE(IsCookieInList(cookie6_with_new_path
, cookies_to_delete
));
2307 // |cookie7| is kept and |cookie7_with_new_path| is added as a new cookie.
2308 EXPECT_FALSE(IsCookieInList(cookie7
, cookies_to_add
));
2309 EXPECT_FALSE(IsCookieInList(cookie7
, cookies_to_delete
));
2310 EXPECT_TRUE(IsCookieInList(cookie7_with_new_path
, cookies_to_add
));
2311 EXPECT_FALSE(IsCookieInList(cookie7_with_new_path
, cookies_to_delete
));
2314 // Check that DeleteAll does flush (as a sanity check that flush_count()
2316 TEST_F(CookieMonsterTest
, DeleteAll
) {
2317 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2318 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2319 cm
->SetPersistSessionCookies(true);
2321 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "X=Y; path=/"));
2323 ASSERT_EQ(0, store
->flush_count());
2324 EXPECT_EQ(1, DeleteAll(cm
.get()));
2325 EXPECT_EQ(1, store
->flush_count());
2328 TEST_F(CookieMonsterTest
, HistogramCheck
) {
2329 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2330 // Should match call in InitializeHistograms, but doesn't really matter
2331 // since the histogram should have been initialized by the CM construction
2333 base::HistogramBase
* expired_histogram
= base::Histogram::FactoryGet(
2334 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2335 base::Histogram::kUmaTargetedHistogramFlag
);
2337 scoped_ptr
<base::HistogramSamples
> samples1(
2338 expired_histogram
->SnapshotSamples());
2339 ASSERT_TRUE(SetCookieWithDetails(
2340 cm
.get(), GURL("http://fake.a.url"), "a", "b", "a.url", "/",
2341 base::Time::Now() + base::TimeDelta::FromMinutes(59), false, false, false,
2342 COOKIE_PRIORITY_DEFAULT
));
2344 scoped_ptr
<base::HistogramSamples
> samples2(
2345 expired_histogram
->SnapshotSamples());
2346 EXPECT_EQ(samples1
->TotalCount() + 1, samples2
->TotalCount());
2348 // kValidCookieLine creates a session cookie.
2349 ASSERT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
2351 scoped_ptr
<base::HistogramSamples
> samples3(
2352 expired_histogram
->SnapshotSamples());
2353 EXPECT_EQ(samples2
->TotalCount(), samples3
->TotalCount());
2358 class MultiThreadedCookieMonsterTest
: public CookieMonsterTest
{
2360 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {}
2362 // Helper methods for calling the asynchronous CookieMonster methods
2363 // from a different thread.
2365 void GetAllCookiesTask(CookieMonster
* cm
, GetCookieListCallback
* callback
) {
2366 cm
->GetAllCookiesAsync(
2367 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2370 void GetAllCookiesForURLTask(CookieMonster
* cm
,
2372 GetCookieListCallback
* callback
) {
2373 cm
->GetAllCookiesForURLAsync(url
, base::Bind(&GetCookieListCallback::Run
,
2374 base::Unretained(callback
)));
2377 void GetAllCookiesForURLWithOptionsTask(CookieMonster
* cm
,
2379 const CookieOptions
& options
,
2380 GetCookieListCallback
* callback
) {
2381 cm
->GetAllCookiesForURLWithOptionsAsync(
2383 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2386 void SetCookieWithDetailsTask(CookieMonster
* cm
,
2388 ResultSavingCookieCallback
<bool>* callback
) {
2389 // Define the parameters here instead of in the calling fucntion.
2390 // The maximum number of parameters for Bind function is 6.
2391 std::string name
= "A";
2392 std::string value
= "B";
2393 std::string domain
= std::string();
2394 std::string path
= "/foo";
2395 base::Time expiration_time
= base::Time();
2396 bool secure
= false;
2397 bool http_only
= false;
2398 bool first_party_only
= false;
2399 CookiePriority priority
= COOKIE_PRIORITY_DEFAULT
;
2400 cm
->SetCookieWithDetailsAsync(
2401 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
2402 first_party_only
, priority
,
2403 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
2404 base::Unretained(callback
)));
2407 void DeleteAllCreatedBetweenTask(CookieMonster
* cm
,
2408 const base::Time
& delete_begin
,
2409 const base::Time
& delete_end
,
2410 ResultSavingCookieCallback
<int>* callback
) {
2411 cm
->DeleteAllCreatedBetweenAsync(
2412 delete_begin
, delete_end
,
2413 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2414 base::Unretained(callback
)));
2417 void DeleteAllForHostTask(CookieMonster
* cm
,
2419 ResultSavingCookieCallback
<int>* callback
) {
2420 cm
->DeleteAllForHostAsync(url
,
2421 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2422 base::Unretained(callback
)));
2425 void DeleteAllCreatedBetweenForHostTask(
2427 const base::Time delete_begin
,
2428 const base::Time delete_end
,
2430 ResultSavingCookieCallback
<int>* callback
) {
2431 cm
->DeleteAllCreatedBetweenForHostAsync(
2432 delete_begin
, delete_end
, url
,
2433 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2434 base::Unretained(callback
)));
2437 void DeleteCanonicalCookieTask(CookieMonster
* cm
,
2438 const CanonicalCookie
& cookie
,
2439 ResultSavingCookieCallback
<bool>* callback
) {
2440 cm
->DeleteCanonicalCookieAsync(
2441 cookie
, base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
2442 base::Unretained(callback
)));
2446 void RunOnOtherThread(const base::Closure
& task
) {
2447 other_thread_
.Start();
2448 other_thread_
.task_runner()->PostTask(FROM_HERE
, task
);
2450 other_thread_
.Stop();
2453 Thread other_thread_
;
2458 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookies
) {
2459 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2460 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2461 CookieList cookies
= GetAllCookies(cm
.get());
2462 CookieList::const_iterator it
= cookies
.begin();
2463 ASSERT_TRUE(it
!= cookies
.end());
2464 EXPECT_EQ("www.google.izzle", it
->Domain());
2465 EXPECT_EQ("A", it
->Name());
2466 ASSERT_TRUE(++it
== cookies
.end());
2467 GetCookieListCallback
callback(&other_thread_
);
2468 base::Closure task
=
2469 base::Bind(&MultiThreadedCookieMonsterTest::GetAllCookiesTask
,
2470 base::Unretained(this), cm
, &callback
);
2471 RunOnOtherThread(task
);
2472 EXPECT_TRUE(callback
.did_run());
2473 it
= callback
.cookies().begin();
2474 ASSERT_TRUE(it
!= callback
.cookies().end());
2475 EXPECT_EQ("www.google.izzle", it
->Domain());
2476 EXPECT_EQ("A", it
->Name());
2477 ASSERT_TRUE(++it
== callback
.cookies().end());
2480 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURL
) {
2481 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2482 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2483 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
2484 CookieList::const_iterator it
= cookies
.begin();
2485 ASSERT_TRUE(it
!= cookies
.end());
2486 EXPECT_EQ("www.google.izzle", it
->Domain());
2487 EXPECT_EQ("A", it
->Name());
2488 ASSERT_TRUE(++it
== cookies
.end());
2489 GetCookieListCallback
callback(&other_thread_
);
2490 base::Closure task
=
2491 base::Bind(&MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask
,
2492 base::Unretained(this), cm
, url_google_
, &callback
);
2493 RunOnOtherThread(task
);
2494 EXPECT_TRUE(callback
.did_run());
2495 it
= callback
.cookies().begin();
2496 ASSERT_TRUE(it
!= callback
.cookies().end());
2497 EXPECT_EQ("www.google.izzle", it
->Domain());
2498 EXPECT_EQ("A", it
->Name());
2499 ASSERT_TRUE(++it
== callback
.cookies().end());
2502 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURLWithOpt
) {
2503 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2504 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2505 CookieOptions options
;
2506 CookieList cookies
=
2507 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, options
);
2508 CookieList::const_iterator it
= cookies
.begin();
2509 ASSERT_TRUE(it
!= cookies
.end());
2510 EXPECT_EQ("www.google.izzle", it
->Domain());
2511 EXPECT_EQ("A", it
->Name());
2512 ASSERT_TRUE(++it
== cookies
.end());
2513 GetCookieListCallback
callback(&other_thread_
);
2514 base::Closure task
= base::Bind(
2515 &MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask
,
2516 base::Unretained(this), cm
, url_google_
, options
, &callback
);
2517 RunOnOtherThread(task
);
2518 EXPECT_TRUE(callback
.did_run());
2519 it
= callback
.cookies().begin();
2520 ASSERT_TRUE(it
!= callback
.cookies().end());
2521 EXPECT_EQ("www.google.izzle", it
->Domain());
2522 EXPECT_EQ("A", it
->Name());
2523 ASSERT_TRUE(++it
== callback
.cookies().end());
2526 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckSetCookieWithDetails
) {
2527 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2528 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A", "B",
2529 std::string(), "/foo", base::Time(), false,
2530 false, false, COOKIE_PRIORITY_DEFAULT
));
2531 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2532 base::Closure task
=
2533 base::Bind(&MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask
,
2534 base::Unretained(this), cm
, url_google_foo_
, &callback
);
2535 RunOnOtherThread(task
);
2536 EXPECT_TRUE(callback
.did_run());
2537 EXPECT_TRUE(callback
.result());
2540 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllCreatedBetween
) {
2541 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2542 CookieOptions options
;
2543 Time now
= Time::Now();
2544 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2545 EXPECT_EQ(1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99),
2547 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2548 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2549 base::Closure task
=
2550 base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask
,
2551 base::Unretained(this), cm
, now
- TimeDelta::FromDays(99),
2553 RunOnOtherThread(task
);
2554 EXPECT_TRUE(callback
.did_run());
2555 EXPECT_EQ(1, callback
.result());
2558 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllForHost
) {
2559 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2560 CookieOptions options
;
2561 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2562 EXPECT_EQ(1, DeleteAllForHost(cm
.get(), url_google_
));
2563 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2564 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2565 base::Closure task
=
2566 base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllForHostTask
,
2567 base::Unretained(this), cm
, url_google_
, &callback
);
2568 RunOnOtherThread(task
);
2569 EXPECT_TRUE(callback
.did_run());
2570 EXPECT_EQ(1, callback
.result());
2573 TEST_F(MultiThreadedCookieMonsterTest
,
2574 ThreadCheckDeleteAllCreatedBetweenForHost
) {
2575 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2576 GURL
url_not_google("http://www.notgoogle.com");
2578 CookieOptions options
;
2579 Time now
= Time::Now();
2580 // ago1 < ago2 < ago3 < now.
2581 Time ago1
= now
- TimeDelta::FromDays(101);
2582 Time ago2
= now
- TimeDelta::FromDays(100);
2583 Time ago3
= now
- TimeDelta::FromDays(99);
2585 // These 3 cookies match the first deletion.
2586 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2587 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "C=D", options
));
2588 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "Y=Z", options
));
2590 // This cookie does not match host.
2591 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_not_google
, "E=F", options
));
2593 // This cookie does not match time range: [ago3, inf], for first deletion, but
2594 // matches for the second deletion.
2595 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "G=H", ago2
));
2597 // 1. First set of deletions.
2599 3, // Deletes A=B, C=D, Y=Z
2600 DeleteAllCreatedBetweenForHost(cm
.get(), ago3
, Time::Max(), url_google_
));
2602 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2603 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2605 // 2. Second set of deletions.
2606 base::Closure task
= base::Bind(
2607 &MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask
,
2608 base::Unretained(this), cm
, ago1
, Time(), url_google_
, &callback
);
2609 RunOnOtherThread(task
);
2610 EXPECT_TRUE(callback
.did_run());
2611 EXPECT_EQ(2, callback
.result()); // Deletes A=B, G=H.
2614 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteCanonicalCookie
) {
2615 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2616 CookieOptions options
;
2617 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2618 CookieList cookies
= GetAllCookies(cm
.get());
2619 CookieList::iterator it
= cookies
.begin();
2620 EXPECT_TRUE(DeleteCanonicalCookie(cm
.get(), *it
));
2622 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2623 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2624 cookies
= GetAllCookies(cm
.get());
2625 it
= cookies
.begin();
2626 base::Closure task
=
2627 base::Bind(&MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask
,
2628 base::Unretained(this), cm
, *it
, &callback
);
2629 RunOnOtherThread(task
);
2630 EXPECT_TRUE(callback
.did_run());
2631 EXPECT_TRUE(callback
.result());
2634 // Ensure that cookies for http, https, ws, and wss all share the same storage
2635 // and policies when GetAllCookiesForURLAsync is used. This test is part of
2636 // MultiThreadedCookieMonsterTest in order to test and use
2637 // GetAllCookiesForURLAsync, but it does not use any additional threads.
2638 TEST_F(MultiThreadedCookieMonsterTest
, GetAllCookiesForURLEffectiveDomain
) {
2639 std::vector
<CanonicalCookie
*> cookies
;
2640 // This cookie will be freed by the CookieMonster.
2641 cookies
.push_back(CanonicalCookie::Create(url_google_
, kValidCookieLine
,
2642 Time::Now(), CookieOptions()));
2643 CanonicalCookie cookie
= *cookies
[0];
2644 scoped_refptr
<NewMockPersistentCookieStore
> store(
2645 new NewMockPersistentCookieStore
);
2646 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2648 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback
;
2649 ::testing::StrictMock
<::testing::MockFunction
<void(int)>> checkpoint
;
2650 const std::string key
=
2651 cookie_util::GetEffectiveDomain(url_google_
.scheme(), url_google_
.host());
2653 ::testing::InSequence s
;
2654 EXPECT_CALL(checkpoint
, Call(0));
2655 EXPECT_CALL(*store
, Load(::testing::_
));
2656 EXPECT_CALL(*store
, LoadCookiesForKey(key
, ::testing::_
))
2657 .WillOnce(::testing::SaveArg
<1>(&loaded_callback
));
2658 EXPECT_CALL(checkpoint
, Call(1));
2659 // LoadCookiesForKey will never be called after checkpoint.Call(1) although
2660 // we will call GetAllCookiesForURLAsync again, because all URLs below share
2662 EXPECT_CALL(*store
, LoadCookiesForKey(::testing::_
, ::testing::_
)).Times(0);
2664 GetCookieListCallback callback
;
2666 GetAllCookiesForURLTask(cm
.get(), url_google_
, &callback
);
2668 ASSERT_FALSE(callback
.did_run());
2669 // Pass the cookies to the CookieMonster.
2670 loaded_callback
.Run(cookies
);
2671 // Now GetAllCookiesForURLTask is done.
2672 ASSERT_TRUE(callback
.did_run());
2673 // See that the callback was called with the cookies.
2674 ASSERT_EQ(1u, callback
.cookies().size());
2675 EXPECT_TRUE(cookie
.IsEquivalent(callback
.cookies()[0]));
2677 // All urls in |urls| should share the same cookie domain.
2678 const GURL kUrls
[] = {
2681 GURL(kUrlGoogleWebSocket
),
2682 GURL(kUrlGoogleWebSocketSecure
),
2684 for (const GURL
& url
: kUrls
) {
2685 // Call the function with |url| and verify it is done synchronously without
2686 // calling LoadCookiesForKey.
2687 GetCookieListCallback callback
;
2688 GetAllCookiesForURLTask(cm
.get(), url
, &callback
);
2689 ASSERT_TRUE(callback
.did_run());
2690 ASSERT_EQ(1u, callback
.cookies().size());
2691 EXPECT_TRUE(cookie
.IsEquivalent(callback
.cookies()[0]));
2695 TEST_F(CookieMonsterTest
, InvalidExpiryTime
) {
2696 std::string cookie_line
=
2697 std::string(kValidCookieLine
) + "; expires=Blarg arg arg";
2698 scoped_ptr
<CanonicalCookie
> cookie(CanonicalCookie::Create(
2699 url_google_
, cookie_line
, Time::Now(), CookieOptions()));
2700 ASSERT_FALSE(cookie
->IsPersistent());
2703 // Test that CookieMonster writes session cookies into the underlying
2704 // CookieStore if the "persist session cookies" option is on.
2705 TEST_F(CookieMonsterTest
, PersistSessionCookies
) {
2706 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2707 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2708 cm
->SetPersistSessionCookies(true);
2710 // All cookies set with SetCookie are session cookies.
2711 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2712 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
2714 // The cookie was written to the backing store.
2715 EXPECT_EQ(1u, store
->commands().size());
2716 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2717 EXPECT_EQ("A", store
->commands()[0].cookie
.Name());
2718 EXPECT_EQ("B", store
->commands()[0].cookie
.Value());
2720 // Modify the cookie.
2721 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=C"));
2722 EXPECT_EQ("A=C", GetCookies(cm
.get(), url_google_
));
2723 EXPECT_EQ(3u, store
->commands().size());
2724 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2725 EXPECT_EQ("A", store
->commands()[1].cookie
.Name());
2726 EXPECT_EQ("B", store
->commands()[1].cookie
.Value());
2727 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2728 EXPECT_EQ("A", store
->commands()[2].cookie
.Name());
2729 EXPECT_EQ("C", store
->commands()[2].cookie
.Value());
2731 // Delete the cookie.
2732 DeleteCookie(cm
.get(), url_google_
, "A");
2733 EXPECT_EQ("", GetCookies(cm
.get(), url_google_
));
2734 EXPECT_EQ(4u, store
->commands().size());
2735 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2736 EXPECT_EQ("A", store
->commands()[3].cookie
.Name());
2737 EXPECT_EQ("C", store
->commands()[3].cookie
.Value());
2740 // Test the commands sent to the persistent cookie store.
2741 TEST_F(CookieMonsterTest
, PersisentCookieStorageTest
) {
2742 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2743 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2746 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2747 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2748 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2749 ASSERT_EQ(1u, store
->commands().size());
2750 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2752 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B; max-age=0"));
2753 this->MatchCookieLines(std::string(), GetCookies(cm
.get(), url_google_
));
2754 ASSERT_EQ(2u, store
->commands().size());
2755 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2758 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2759 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2760 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2761 ASSERT_EQ(3u, store
->commands().size());
2762 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2764 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2765 "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
2766 this->MatchCookieLines("A=Foo", GetCookies(cm
.get(), url_google_
));
2767 ASSERT_EQ(5u, store
->commands().size());
2768 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2769 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[4].type
);
2771 // Create some non-persistent cookies and check that they don't go to the
2772 // persistent storage.
2773 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=Bar"));
2774 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm
.get(), url_google_
));
2775 EXPECT_EQ(5u, store
->commands().size());
2778 // Test to assure that cookies with control characters are purged appropriately.
2779 // See http://crbug.com/238041 for background.
2780 TEST_F(CookieMonsterTest
, ControlCharacterPurge
) {
2781 const Time
now1(Time::Now());
2782 const Time
now2(Time::Now() + TimeDelta::FromSeconds(1));
2783 const Time
now3(Time::Now() + TimeDelta::FromSeconds(2));
2784 const Time
later(now1
+ TimeDelta::FromDays(1));
2785 const GURL
url("http://host/path");
2786 const std::string
domain("host");
2787 const std::string
path("/path");
2789 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2791 std::vector
<CanonicalCookie
*> initial_cookies
;
2793 AddCookieToList(domain
, "foo=bar; path=" + path
, now1
, &initial_cookies
);
2795 // We have to manually build this cookie because it contains a control
2796 // character, and our cookie line parser rejects control characters.
2797 CanonicalCookie
* cc
=
2798 new CanonicalCookie(url
, "baz",
2801 domain
, path
, now2
, later
, now2
, false, false, false,
2802 COOKIE_PRIORITY_DEFAULT
);
2803 initial_cookies
.push_back(cc
);
2805 AddCookieToList(domain
, "hello=world; path=" + path
, now3
, &initial_cookies
);
2807 // Inject our initial cookies into the mock PersistentCookieStore.
2808 store
->SetLoadExpectation(true, initial_cookies
);
2810 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2812 EXPECT_EQ("foo=bar; hello=world", GetCookies(cm
.get(), url
));
2815 // Test that cookie source schemes are histogrammed correctly.
2816 TEST_F(CookieMonsterTest
, CookieSourceHistogram
) {
2817 base::HistogramTester histograms
;
2818 const std::string cookie_source_histogram
= "Cookie.CookieSourceScheme";
2820 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2821 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2823 histograms
.ExpectTotalCount(cookie_source_histogram
, 0);
2825 // Set a Secure cookie on a cryptographic scheme.
2826 EXPECT_TRUE(SetCookie(cm
.get(), url_google_secure_
, "A=B; path=/; Secure"));
2827 histograms
.ExpectTotalCount(cookie_source_histogram
, 1);
2828 histograms
.ExpectBucketCount(
2829 cookie_source_histogram
,
2830 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
, 1);
2832 // Set a non-Secure cookie on a cryptographic scheme.
2833 EXPECT_TRUE(SetCookie(cm
.get(), url_google_secure_
, "C=D; path=/;"));
2834 histograms
.ExpectTotalCount(cookie_source_histogram
, 2);
2835 histograms
.ExpectBucketCount(
2836 cookie_source_histogram
,
2837 CookieMonster::COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
, 1);
2839 // Set a Secure cookie on a non-cryptographic scheme.
2840 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "D=E; path=/; Secure"));
2841 histograms
.ExpectTotalCount(cookie_source_histogram
, 3);
2842 histograms
.ExpectBucketCount(
2843 cookie_source_histogram
,
2844 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
, 1);
2846 // Overwrite a Secure cookie (set by a cryptographic scheme) on a
2847 // non-cryptographic scheme.
2848 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B; path=/; Secure"));
2849 histograms
.ExpectTotalCount(cookie_source_histogram
, 4);
2850 histograms
.ExpectBucketCount(
2851 cookie_source_histogram
,
2852 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
, 1);
2853 histograms
.ExpectBucketCount(
2854 cookie_source_histogram
,
2855 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
, 2);
2857 // Test that clearing a Secure cookie on a http:// URL does not get
2859 EXPECT_TRUE(SetCookie(cm
.get(), url_google_secure_
, "F=G; path=/; Secure"));
2860 histograms
.ExpectTotalCount(cookie_source_histogram
, 5);
2861 std::string cookies1
= GetCookies(cm
.get(), url_google_secure_
);
2862 EXPECT_NE(std::string::npos
, cookies1
.find("F=G"));
2863 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2864 "F=G; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"));
2865 std::string cookies2
= GetCookies(cm
.get(), url_google_secure_
);
2866 EXPECT_EQ(std::string::npos
, cookies2
.find("F=G"));
2867 histograms
.ExpectTotalCount(cookie_source_histogram
, 5);
2869 // Set a non-Secure cookie on a non-cryptographic scheme.
2870 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "H=I; path=/"));
2871 histograms
.ExpectTotalCount(cookie_source_histogram
, 6);
2872 histograms
.ExpectBucketCount(
2873 cookie_source_histogram
,
2874 CookieMonster::COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
, 1);
2877 class CookieMonsterNotificationTest
: public CookieMonsterTest
{
2879 CookieMonsterNotificationTest()
2880 : test_url_("http://www.google.com/foo"),
2881 store_(new MockPersistentCookieStore
),
2882 monster_(new CookieMonster(store_
.get(), NULL
)) {}
2884 ~CookieMonsterNotificationTest() override
{}
2886 CookieMonster
* monster() { return monster_
.get(); }
2889 const GURL test_url_
;
2892 scoped_refptr
<MockPersistentCookieStore
> store_
;
2893 scoped_refptr
<CookieMonster
> monster_
;
2896 void RecordCookieChanges(std::vector
<CanonicalCookie
>* out_cookies
,
2897 std::vector
<bool>* out_removes
,
2898 const CanonicalCookie
& cookie
,
2900 DCHECK(out_cookies
);
2901 out_cookies
->push_back(cookie
);
2903 out_removes
->push_back(removed
);
2906 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithNoCookie
) {
2907 std::vector
<CanonicalCookie
> cookies
;
2908 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2909 monster()->AddCallbackForCookie(
2911 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2912 base::MessageLoop::current()->RunUntilIdle();
2913 EXPECT_EQ(0U, cookies
.size());
2916 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithInitialCookie
) {
2917 std::vector
<CanonicalCookie
> cookies
;
2918 SetCookie(monster(), test_url_
, "abc=def");
2919 base::MessageLoop::current()->RunUntilIdle();
2920 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2921 monster()->AddCallbackForCookie(
2923 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2924 base::MessageLoop::current()->RunUntilIdle();
2925 EXPECT_EQ(0U, cookies
.size());
2928 TEST_F(CookieMonsterNotificationTest
, NotifyOnSet
) {
2929 std::vector
<CanonicalCookie
> cookies
;
2930 std::vector
<bool> removes
;
2931 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2932 monster()->AddCallbackForCookie(
2934 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2935 SetCookie(monster(), test_url_
, "abc=def");
2936 base::MessageLoop::current()->RunUntilIdle();
2937 EXPECT_EQ(1U, cookies
.size());
2938 EXPECT_EQ(1U, removes
.size());
2940 EXPECT_EQ("abc", cookies
[0].Name());
2941 EXPECT_EQ("def", cookies
[0].Value());
2942 EXPECT_FALSE(removes
[0]);
2945 TEST_F(CookieMonsterNotificationTest
, NotifyOnDelete
) {
2946 std::vector
<CanonicalCookie
> cookies
;
2947 std::vector
<bool> removes
;
2948 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2949 monster()->AddCallbackForCookie(
2951 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2952 SetCookie(monster(), test_url_
, "abc=def");
2953 base::MessageLoop::current()->RunUntilIdle();
2954 EXPECT_EQ(1U, cookies
.size());
2955 EXPECT_EQ(1U, removes
.size());
2957 DeleteCookie(monster(), test_url_
, "abc");
2958 base::MessageLoop::current()->RunUntilIdle();
2959 EXPECT_EQ(2U, cookies
.size());
2960 EXPECT_EQ(2U, removes
.size());
2962 EXPECT_EQ("abc", cookies
[1].Name());
2963 EXPECT_EQ("def", cookies
[1].Value());
2964 EXPECT_TRUE(removes
[1]);
2967 TEST_F(CookieMonsterNotificationTest
, NotifyOnUpdate
) {
2968 std::vector
<CanonicalCookie
> cookies
;
2969 std::vector
<bool> removes
;
2970 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2971 monster()->AddCallbackForCookie(
2973 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2974 SetCookie(monster(), test_url_
, "abc=def");
2975 base::MessageLoop::current()->RunUntilIdle();
2976 EXPECT_EQ(1U, cookies
.size());
2978 // Replacing an existing cookie is actually a two-phase delete + set
2979 // operation, so we get an extra notification.
2980 SetCookie(monster(), test_url_
, "abc=ghi");
2981 base::MessageLoop::current()->RunUntilIdle();
2983 EXPECT_EQ(3U, cookies
.size());
2984 EXPECT_EQ(3U, removes
.size());
2986 EXPECT_EQ("abc", cookies
[1].Name());
2987 EXPECT_EQ("def", cookies
[1].Value());
2988 EXPECT_TRUE(removes
[1]);
2990 EXPECT_EQ("abc", cookies
[2].Name());
2991 EXPECT_EQ("ghi", cookies
[2].Value());
2992 EXPECT_FALSE(removes
[2]);
2995 TEST_F(CookieMonsterNotificationTest
, MultipleNotifies
) {
2996 std::vector
<CanonicalCookie
> cookies0
;
2997 std::vector
<CanonicalCookie
> cookies1
;
2998 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
2999 monster()->AddCallbackForCookie(
3001 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
3002 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
3003 monster()->AddCallbackForCookie(
3005 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
3006 SetCookie(monster(), test_url_
, "abc=def");
3007 base::MessageLoop::current()->RunUntilIdle();
3008 EXPECT_EQ(1U, cookies0
.size());
3009 EXPECT_EQ(0U, cookies1
.size());
3010 SetCookie(monster(), test_url_
, "def=abc");
3011 base::MessageLoop::current()->RunUntilIdle();
3012 EXPECT_EQ(1U, cookies0
.size());
3013 EXPECT_EQ(1U, cookies1
.size());
3016 TEST_F(CookieMonsterNotificationTest
, MultipleSameNotifies
) {
3017 std::vector
<CanonicalCookie
> cookies0
;
3018 std::vector
<CanonicalCookie
> cookies1
;
3019 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
3020 monster()->AddCallbackForCookie(
3022 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
3023 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
3024 monster()->AddCallbackForCookie(
3026 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
3027 SetCookie(monster(), test_url_
, "abc=def");
3028 base::MessageLoop::current()->RunUntilIdle();
3029 EXPECT_EQ(1U, cookies0
.size());
3030 EXPECT_EQ(1U, cookies0
.size());