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/thread_task_runner_handle.h"
27 #include "base/threading/thread.h"
28 #include "base/time/time.h"
29 #include "net/cookies/canonical_cookie.h"
30 #include "net/cookies/cookie_constants.h"
31 #include "net/cookies/cookie_monster.h"
32 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
33 #include "net/cookies/cookie_util.h"
34 #include "net/cookies/parsed_cookie.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h"
42 using base::TimeDelta
;
46 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and
47 // brethren) with this one, and remove the 'New' prefix.
48 class NewMockPersistentCookieStore
49 : public CookieMonster::PersistentCookieStore
{
51 MOCK_METHOD1(Load
, void(const LoadedCallback
& loaded_callback
));
52 MOCK_METHOD2(LoadCookiesForKey
,
53 void(const std::string
& key
,
54 const LoadedCallback
& loaded_callback
));
55 MOCK_METHOD1(AddCookie
, void(const CanonicalCookie
& cc
));
56 MOCK_METHOD1(UpdateCookieAccessTime
, void(const CanonicalCookie
& cc
));
57 MOCK_METHOD1(DeleteCookie
, void(const CanonicalCookie
& cc
));
58 virtual void Flush(const base::Closure
& callback
) {
59 if (!callback
.is_null())
60 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
62 MOCK_METHOD0(SetForceKeepSessionState
, void());
65 virtual ~NewMockPersistentCookieStore() {}
68 const char kTopLevelDomainPlus1
[] = "http://www.harvard.edu";
69 const char kTopLevelDomainPlus2
[] = "http://www.math.harvard.edu";
70 const char kTopLevelDomainPlus2Secure
[] = "https://www.math.harvard.edu";
71 const char kTopLevelDomainPlus3
[] = "http://www.bourbaki.math.harvard.edu";
72 const char kOtherDomain
[] = "http://www.mit.edu";
73 const char kUrlGoogleSpecific
[] = "http://www.gmail.google.izzle";
75 class GetCookieListCallback
: public CookieCallback
{
77 GetCookieListCallback() {}
78 explicit GetCookieListCallback(Thread
* run_in_thread
)
79 : CookieCallback(run_in_thread
) {}
81 void Run(const CookieList
& cookies
) {
86 const CookieList
& cookies() { return cookies_
; }
92 struct CookieMonsterTestTraits
{
93 static scoped_refptr
<CookieStore
> Create() {
94 return new CookieMonster(NULL
, NULL
);
97 static const bool is_cookie_monster
= true;
98 static const bool supports_http_only
= true;
99 static const bool supports_non_dotted_domains
= true;
100 static const bool supports_trailing_dots
= true;
101 static const bool filters_schemes
= true;
102 static const bool has_path_prefix_bug
= false;
103 static const int creation_time_granularity_in_ms
= 0;
106 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
108 CookieMonsterTestTraits
);
110 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
111 MultiThreadedCookieStoreTest
,
112 CookieMonsterTestTraits
);
114 class CookieMonsterTest
: public CookieStoreTest
<CookieMonsterTestTraits
> {
116 CookieList
GetAllCookies(CookieMonster
* cm
) {
118 GetCookieListCallback callback
;
119 cm
->GetAllCookiesAsync(
120 base::Bind(&GetCookieListCallback::Run
, base::Unretained(&callback
)));
122 EXPECT_TRUE(callback
.did_run());
123 return callback
.cookies();
126 CookieList
GetAllCookiesForURL(CookieMonster
* cm
, const GURL
& url
) {
128 GetCookieListCallback callback
;
129 cm
->GetAllCookiesForURLAsync(url
, base::Bind(&GetCookieListCallback::Run
,
130 base::Unretained(&callback
)));
132 EXPECT_TRUE(callback
.did_run());
133 return callback
.cookies();
136 CookieList
GetAllCookiesForURLWithOptions(CookieMonster
* cm
,
138 const CookieOptions
& options
) {
140 GetCookieListCallback callback
;
141 cm
->GetAllCookiesForURLWithOptionsAsync(
143 base::Bind(&GetCookieListCallback::Run
, base::Unretained(&callback
)));
145 EXPECT_TRUE(callback
.did_run());
146 return callback
.cookies();
149 bool SetCookieWithDetails(CookieMonster
* cm
,
151 const std::string
& name
,
152 const std::string
& value
,
153 const std::string
& domain
,
154 const std::string
& path
,
155 const base::Time
& expiration_time
,
158 bool first_party_only
,
159 CookiePriority priority
) {
161 ResultSavingCookieCallback
<bool> callback
;
162 cm
->SetCookieWithDetailsAsync(
163 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
164 first_party_only
, priority
,
165 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
166 base::Unretained(&callback
)));
168 EXPECT_TRUE(callback
.did_run());
169 return callback
.result();
172 bool SetAllCookies(CookieMonster
* cm
, const CookieList
& list
) {
174 ResultSavingCookieCallback
<bool> callback
;
175 cm
->SetAllCookiesAsync(list
,
176 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
177 base::Unretained(&callback
)));
179 EXPECT_TRUE(callback
.did_run());
180 return callback
.result();
183 int DeleteAll(CookieMonster
* cm
) {
185 ResultSavingCookieCallback
<int> callback
;
186 cm
->DeleteAllAsync(base::Bind(&ResultSavingCookieCallback
<int>::Run
,
187 base::Unretained(&callback
)));
189 EXPECT_TRUE(callback
.did_run());
190 return callback
.result();
193 int DeleteAllCreatedBetween(CookieMonster
* cm
,
194 const base::Time
& delete_begin
,
195 const base::Time
& delete_end
) {
197 ResultSavingCookieCallback
<int> callback
;
198 cm
->DeleteAllCreatedBetweenAsync(
199 delete_begin
, delete_end
,
200 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
201 base::Unretained(&callback
)));
203 EXPECT_TRUE(callback
.did_run());
204 return callback
.result();
207 int DeleteAllCreatedBetweenForHost(CookieMonster
* cm
,
208 const base::Time delete_begin
,
209 const base::Time delete_end
,
212 ResultSavingCookieCallback
<int> callback
;
213 cm
->DeleteAllCreatedBetweenForHostAsync(
214 delete_begin
, delete_end
, url
,
215 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
216 base::Unretained(&callback
)));
218 EXPECT_TRUE(callback
.did_run());
219 return callback
.result();
222 int DeleteAllForHost(CookieMonster
* cm
, const GURL
& url
) {
224 ResultSavingCookieCallback
<int> callback
;
225 cm
->DeleteAllForHostAsync(url
,
226 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
227 base::Unretained(&callback
)));
229 EXPECT_TRUE(callback
.did_run());
230 return callback
.result();
233 bool DeleteCanonicalCookie(CookieMonster
* cm
, const CanonicalCookie
& cookie
) {
235 ResultSavingCookieCallback
<bool> callback
;
236 cm
->DeleteCanonicalCookieAsync(
237 cookie
, base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
238 base::Unretained(&callback
)));
240 EXPECT_TRUE(callback
.did_run());
241 return callback
.result();
244 // Helper for DeleteAllForHost test; repopulates CM with same layout
246 void PopulateCmForDeleteAllForHost(scoped_refptr
<CookieMonster
> cm
) {
247 GURL
url_top_level_domain_plus_1(kTopLevelDomainPlus1
);
248 GURL
url_top_level_domain_plus_2(kTopLevelDomainPlus2
);
249 GURL
url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure
);
250 GURL
url_top_level_domain_plus_3(kTopLevelDomainPlus3
);
251 GURL
url_other(kOtherDomain
);
255 // Static population for probe:
256 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
257 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
258 // * http_only cookie (w.c.b.a)
259 // * first-party cookie (w.c.b.a)
260 // * Two secure cookies (.c.b.a, w.c.b.a)
261 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
262 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
265 EXPECT_TRUE(this->SetCookieWithDetails(
266 cm
.get(), url_top_level_domain_plus_1
, "dom_1", "X", ".harvard.edu",
267 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
268 EXPECT_TRUE(this->SetCookieWithDetails(
269 cm
.get(), url_top_level_domain_plus_2
, "dom_2", "X",
270 ".math.harvard.edu", "/", base::Time(), false, false, false,
271 COOKIE_PRIORITY_DEFAULT
));
272 EXPECT_TRUE(this->SetCookieWithDetails(
273 cm
.get(), url_top_level_domain_plus_3
, "dom_3", "X",
274 ".bourbaki.math.harvard.edu", "/", base::Time(), false, false, false,
275 COOKIE_PRIORITY_DEFAULT
));
278 EXPECT_TRUE(this->SetCookieWithDetails(
279 cm
.get(), url_top_level_domain_plus_1
, "host_1", "X", std::string(),
280 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
281 EXPECT_TRUE(this->SetCookieWithDetails(
282 cm
.get(), url_top_level_domain_plus_2
, "host_2", "X", std::string(),
283 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
284 EXPECT_TRUE(this->SetCookieWithDetails(
285 cm
.get(), url_top_level_domain_plus_3
, "host_3", "X", std::string(),
286 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
289 EXPECT_TRUE(this->SetCookieWithDetails(
290 cm
.get(), url_top_level_domain_plus_2
, "httpo_check", "x",
291 std::string(), "/", base::Time(), false, true, false,
292 COOKIE_PRIORITY_DEFAULT
));
294 // first-party cookie
295 EXPECT_TRUE(this->SetCookieWithDetails(
296 cm
.get(), url_top_level_domain_plus_2
, "firstp_check", "x",
297 std::string(), "/", base::Time(), false, false, true,
298 COOKIE_PRIORITY_DEFAULT
));
301 EXPECT_TRUE(this->SetCookieWithDetails(
302 cm
.get(), url_top_level_domain_plus_2_secure
, "sec_dom", "X",
303 ".math.harvard.edu", "/", base::Time(), true, false, false,
304 COOKIE_PRIORITY_DEFAULT
));
305 EXPECT_TRUE(this->SetCookieWithDetails(
306 cm
.get(), url_top_level_domain_plus_2_secure
, "sec_host", "X",
307 std::string(), "/", base::Time(), true, false, false,
308 COOKIE_PRIORITY_DEFAULT
));
310 // Domain path cookies
311 EXPECT_TRUE(this->SetCookieWithDetails(
312 cm
.get(), url_top_level_domain_plus_2
, "dom_path_1", "X",
313 ".math.harvard.edu", "/dir1", base::Time(), false, false, false,
314 COOKIE_PRIORITY_DEFAULT
));
315 EXPECT_TRUE(this->SetCookieWithDetails(
316 cm
.get(), url_top_level_domain_plus_2
, "dom_path_2", "X",
317 ".math.harvard.edu", "/dir1/dir2", base::Time(), false, false, false,
318 COOKIE_PRIORITY_DEFAULT
));
321 EXPECT_TRUE(this->SetCookieWithDetails(
322 cm
.get(), url_top_level_domain_plus_2
, "host_path_1", "X",
323 std::string(), "/dir1", base::Time(), false, false, false,
324 COOKIE_PRIORITY_DEFAULT
));
325 EXPECT_TRUE(this->SetCookieWithDetails(
326 cm
.get(), url_top_level_domain_plus_2
, "host_path_2", "X",
327 std::string(), "/dir1/dir2", base::Time(), false, false, false,
328 COOKIE_PRIORITY_DEFAULT
));
330 EXPECT_EQ(14U, this->GetAllCookies(cm
.get()).size());
333 Time
GetFirstCookieAccessDate(CookieMonster
* cm
) {
334 const CookieList
all_cookies(this->GetAllCookies(cm
));
335 return all_cookies
.front().LastAccessDate();
338 bool FindAndDeleteCookie(CookieMonster
* cm
,
339 const std::string
& domain
,
340 const std::string
& name
) {
341 CookieList cookies
= this->GetAllCookies(cm
);
342 for (CookieList::iterator it
= cookies
.begin(); it
!= cookies
.end(); ++it
)
343 if (it
->Domain() == domain
&& it
->Name() == name
)
344 return this->DeleteCanonicalCookie(cm
, *it
);
348 int CountInString(const std::string
& str
, char c
) {
349 return std::count(str
.begin(), str
.end(), c
);
352 void TestHostGarbageCollectHelper() {
353 int domain_max_cookies
= CookieMonster::kDomainMaxCookies
;
354 int domain_purge_cookies
= CookieMonster::kDomainPurgeCookies
;
355 const int more_than_enough_cookies
=
356 (domain_max_cookies
+ domain_purge_cookies
) * 2;
357 // Add a bunch of cookies on a single host, should purge them.
359 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
360 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
361 std::string cookie
= base::StringPrintf("a%03d=b", i
);
362 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie
));
363 std::string cookies
= this->GetCookies(cm
.get(), url_google_
);
364 // Make sure we find it in the cookies.
365 EXPECT_NE(cookies
.find(cookie
), std::string::npos
);
366 // Count the number of cookies.
367 EXPECT_LE(CountInString(cookies
, '='), domain_max_cookies
);
371 // Add a bunch of cookies on multiple hosts within a single eTLD.
372 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
373 // between them. We shouldn't go above kDomainMaxCookies for both together.
374 GURL
url_google_specific(kUrlGoogleSpecific
);
376 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
377 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
378 std::string cookie_general
= base::StringPrintf("a%03d=b", i
);
379 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie_general
));
380 std::string cookie_specific
= base::StringPrintf("c%03d=b", i
);
381 EXPECT_TRUE(SetCookie(cm
.get(), url_google_specific
, cookie_specific
));
382 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
383 EXPECT_NE(cookies_general
.find(cookie_general
), std::string::npos
);
384 std::string cookies_specific
=
385 this->GetCookies(cm
.get(), url_google_specific
);
386 EXPECT_NE(cookies_specific
.find(cookie_specific
), std::string::npos
);
387 EXPECT_LE((CountInString(cookies_general
, '=') +
388 CountInString(cookies_specific
, '=')),
391 // After all this, there should be at least
392 // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
393 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
394 std::string cookies_specific
=
395 this->GetCookies(cm
.get(), url_google_specific
);
396 int total_cookies
= (CountInString(cookies_general
, '=') +
397 CountInString(cookies_specific
, '='));
398 EXPECT_GE(total_cookies
, domain_max_cookies
- domain_purge_cookies
);
399 EXPECT_LE(total_cookies
, domain_max_cookies
);
403 CookiePriority
CharToPriority(char ch
) {
406 return COOKIE_PRIORITY_LOW
;
408 return COOKIE_PRIORITY_MEDIUM
;
410 return COOKIE_PRIORITY_HIGH
;
413 return COOKIE_PRIORITY_DEFAULT
;
416 // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
417 // priorities specified by |coded_priority_str|, and tests priority-aware
418 // domain cookie eviction.
419 // |coded_priority_str| specifies a run-length-encoded string of priorities.
420 // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
421 // from least- to most-recently accessed) insertion of 2 medium-priority
422 // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4
423 // high-priority cookies.
424 // Within each priority, only the least-accessed cookies should be evicted.
425 // Thus, to describe expected suriving cookies, it suffices to specify the
426 // expected population of surviving cookies per priority, i.e.,
427 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
428 void TestPriorityCookieCase(CookieMonster
* cm
,
429 const std::string
& coded_priority_str
,
430 size_t expected_low_count
,
431 size_t expected_medium_count
,
432 size_t expected_high_count
) {
434 int next_cookie_id
= 0;
435 std::vector
<CookiePriority
> priority_list
;
436 std::vector
<int> id_list
[3]; // Indexed by CookiePriority.
438 // Parse |coded_priority_str| and add cookies.
439 std::vector
<std::string
> priority_tok_list
;
440 base::SplitString(coded_priority_str
, ' ', &priority_tok_list
);
441 for (std::vector
<std::string
>::iterator it
= priority_tok_list
.begin();
442 it
!= priority_tok_list
.end(); ++it
) {
443 size_t len
= it
->length();
445 // Take last character as priority.
446 CookiePriority priority
= CharToPriority((*it
)[len
- 1]);
447 std::string priority_str
= CookiePriorityToString(priority
);
448 // The rest of the string (possibly empty) specifies repetition.
451 bool result
= base::StringToInt(
452 base::StringPiece(it
->begin(), it
->end() - 1), &rep
);
455 for (; rep
> 0; --rep
, ++next_cookie_id
) {
456 std::string cookie
= base::StringPrintf(
457 "a%d=b;priority=%s", next_cookie_id
, priority_str
.c_str());
458 EXPECT_TRUE(SetCookie(cm
, url_google_
, cookie
));
459 priority_list
.push_back(priority
);
460 id_list
[priority
].push_back(next_cookie_id
);
464 int num_cookies
= static_cast<int>(priority_list
.size());
465 std::vector
<int> surviving_id_list
[3]; // Indexed by CookiePriority.
467 // Parse the list of cookies
468 std::string cookie_str
= this->GetCookies(cm
, url_google_
);
469 std::vector
<std::string
> cookie_tok_list
;
470 base::SplitString(cookie_str
, ';', &cookie_tok_list
);
471 for (std::vector
<std::string
>::iterator it
= cookie_tok_list
.begin();
472 it
!= cookie_tok_list
.end(); ++it
) {
473 // Assuming *it is "a#=b", so extract and parse "#" portion.
475 bool result
= base::StringToInt(
476 base::StringPiece(it
->begin() + 1, it
->end() - 2), &id
);
479 DCHECK_LT(id
, num_cookies
);
480 surviving_id_list
[priority_list
[id
]].push_back(id
);
483 // Validate each priority.
484 size_t expected_count
[3] = {
485 expected_low_count
, expected_medium_count
, expected_high_count
};
486 for (int i
= 0; i
< 3; ++i
) {
487 DCHECK_LE(surviving_id_list
[i
].size(), id_list
[i
].size());
488 EXPECT_EQ(expected_count
[i
], surviving_id_list
[i
].size());
489 // Verify that the remaining cookies are the most recent among those
490 // with the same priorities.
491 if (expected_count
[i
] == surviving_id_list
[i
].size()) {
492 std::sort(surviving_id_list
[i
].begin(), surviving_id_list
[i
].end());
493 EXPECT_TRUE(std::equal(surviving_id_list
[i
].begin(),
494 surviving_id_list
[i
].end(),
495 id_list
[i
].end() - expected_count
[i
]));
500 void TestPriorityAwareGarbageCollectHelper() {
501 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
502 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies
);
503 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies
-
504 CookieMonster::kDomainPurgeCookies
);
505 DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow
);
506 DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium
);
507 DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh
);
509 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
511 // Each test case adds 181 cookies, so 31 cookies are evicted.
512 // Cookie same priority, repeated for each priority.
513 TestPriorityCookieCase(cm
.get(), "181L", 150U, 0U, 0U);
514 TestPriorityCookieCase(cm
.get(), "181M", 0U, 150U, 0U);
515 TestPriorityCookieCase(cm
.get(), "181H", 0U, 0U, 150U);
517 // Pairwise scenarios.
518 // Round 1 => none; round2 => 31M; round 3 => none.
519 TestPriorityCookieCase(cm
.get(), "10H 171M", 0U, 140U, 10U);
520 // Round 1 => 10L; round2 => 21M; round 3 => none.
521 TestPriorityCookieCase(cm
.get(), "141M 40L", 30U, 120U, 0U);
522 // Round 1 => none; round2 => none; round 3 => 31H.
523 TestPriorityCookieCase(cm
.get(), "101H 80M", 0U, 80U, 70U);
525 // For {low, medium} priorities right on quota, different orders.
526 // Round 1 => 1L; round 2 => none, round3 => 30L.
527 TestPriorityCookieCase(cm
.get(), "31L 50M 100H", 0U, 50U, 100U);
528 // Round 1 => none; round 2 => 1M, round3 => 30M.
529 TestPriorityCookieCase(cm
.get(), "51M 100H 30L", 30U, 20U, 100U);
530 // Round 1 => none; round 2 => none; round3 => 31H.
531 TestPriorityCookieCase(cm
.get(), "101H 50M 30L", 30U, 50U, 70U);
533 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
534 TestPriorityCookieCase(cm
.get(), "81H 60M 40L", 30U, 50U, 70U);
536 // More complex scenarios.
537 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
538 TestPriorityCookieCase(cm
.get(), "21H 60M 40L 60H", 30U, 50U, 70U);
539 // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
540 TestPriorityCookieCase(cm
.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U,
542 // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
543 TestPriorityCookieCase(cm
.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U);
544 // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
545 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U);
546 // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
547 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U);
550 // Function for creating a CM with a number of cookies in it,
551 // no store (and hence no ability to affect access time).
552 CookieMonster
* CreateMonsterForGC(int num_cookies
) {
553 CookieMonster
* cm(new CookieMonster(NULL
, NULL
));
554 for (int i
= 0; i
< num_cookies
; i
++) {
555 SetCookie(cm
, GURL(base::StringPrintf("http://h%05d.izzle", i
)), "a=1");
560 bool IsCookieInList(const CanonicalCookie
& cookie
, const CookieList
& list
) {
561 for (CookieList::const_iterator it
= list
.begin(); it
!= list
.end(); ++it
) {
562 if (it
->Source() == cookie
.Source() && it
->Name() == cookie
.Name() &&
563 it
->Value() == cookie
.Value() && it
->Domain() == cookie
.Domain() &&
564 it
->Path() == cookie
.Path() &&
565 it
->CreationDate() == cookie
.CreationDate() &&
566 it
->ExpiryDate() == cookie
.ExpiryDate() &&
567 it
->LastAccessDate() == cookie
.LastAccessDate() &&
568 it
->IsSecure() == cookie
.IsSecure() &&
569 it
->IsHttpOnly() == cookie
.IsHttpOnly() &&
570 it
->Priority() == cookie
.Priority()) {
579 // TODO(erikwright): Replace the other callbacks and synchronous helper methods
580 // in this test suite with these Mocks.
581 template <typename T
, typename C
>
582 class MockCookieCallback
{
585 return base::Bind(&T::Invoke
, base::Unretained(static_cast<T
*>(this)));
589 class MockGetCookiesCallback
590 : public MockCookieCallback
<MockGetCookiesCallback
,
591 CookieStore::GetCookiesCallback
> {
593 MOCK_METHOD1(Invoke
, void(const std::string
& cookies
));
596 class MockSetCookiesCallback
597 : public MockCookieCallback
<MockSetCookiesCallback
,
598 CookieStore::SetCookiesCallback
> {
600 MOCK_METHOD1(Invoke
, void(bool success
));
603 class MockClosure
: public MockCookieCallback
<MockClosure
, base::Closure
> {
605 MOCK_METHOD0(Invoke
, void(void));
608 class MockGetCookieListCallback
609 : public MockCookieCallback
<MockGetCookieListCallback
,
610 CookieMonster::GetCookieListCallback
> {
612 MOCK_METHOD1(Invoke
, void(const CookieList
& cookies
));
615 class MockDeleteCallback
616 : public MockCookieCallback
<MockDeleteCallback
,
617 CookieMonster::DeleteCallback
> {
619 MOCK_METHOD1(Invoke
, void(int num_deleted
));
622 class MockDeleteCookieCallback
623 : public MockCookieCallback
<MockDeleteCookieCallback
,
624 CookieMonster::DeleteCookieCallback
> {
626 MOCK_METHOD1(Invoke
, void(bool success
));
629 struct CookiesInputInfo
{
631 const std::string name
;
632 const std::string value
;
633 const std::string domain
;
634 const std::string path
;
635 const base::Time expiration_time
;
638 bool first_party_only
;
639 CookiePriority priority
;
642 ACTION(QuitCurrentMessageLoop
) {
643 base::ThreadTaskRunnerHandle::Get()->PostTask(
644 FROM_HERE
, base::MessageLoop::QuitClosure());
647 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
648 // rename these, removing the 'Action' suffix.
649 ACTION_P4(DeleteCookieAction
, cookie_monster
, url
, name
, callback
) {
650 cookie_monster
->DeleteCookieAsync(url
, name
, callback
->AsCallback());
652 ACTION_P3(GetCookiesAction
, cookie_monster
, url
, callback
) {
653 cookie_monster
->GetCookiesWithOptionsAsync(url
, CookieOptions(),
654 callback
->AsCallback());
656 ACTION_P4(SetCookieAction
, cookie_monster
, url
, cookie_line
, callback
) {
657 cookie_monster
->SetCookieWithOptionsAsync(url
, cookie_line
, CookieOptions(),
658 callback
->AsCallback());
660 ACTION_P3(SetAllCookiesAction
, cookie_monster
, list
, callback
) {
661 cookie_monster
->SetAllCookiesAsync(list
, callback
->AsCallback());
663 ACTION_P4(DeleteAllCreatedBetweenAction
,
668 cookie_monster
->DeleteAllCreatedBetweenAsync(delete_begin
, delete_end
,
669 callback
->AsCallback());
671 ACTION_P3(SetCookieWithDetailsAction
, cookie_monster
, cc
, callback
) {
672 cookie_monster
->SetCookieWithDetailsAsync(
673 cc
.url
, cc
.name
, cc
.value
, cc
.domain
, cc
.path
, cc
.expiration_time
,
674 cc
.secure
, cc
.http_only
, cc
.first_party_only
, cc
.priority
,
675 callback
->AsCallback());
678 ACTION_P2(GetAllCookiesAction
, cookie_monster
, callback
) {
679 cookie_monster
->GetAllCookiesAsync(callback
->AsCallback());
682 ACTION_P3(DeleteAllForHostAction
, cookie_monster
, url
, callback
) {
683 cookie_monster
->DeleteAllForHostAsync(url
, callback
->AsCallback());
686 ACTION_P3(DeleteCanonicalCookieAction
, cookie_monster
, cookie
, callback
) {
687 cookie_monster
->DeleteCanonicalCookieAsync(cookie
, callback
->AsCallback());
690 ACTION_P2(DeleteAllAction
, cookie_monster
, callback
) {
691 cookie_monster
->DeleteAllAsync(callback
->AsCallback());
694 ACTION_P3(GetAllCookiesForUrlWithOptionsAction
, cookie_monster
, url
, callback
) {
695 cookie_monster
->GetAllCookiesForURLWithOptionsAsync(url
, CookieOptions(),
696 callback
->AsCallback());
699 ACTION_P3(GetAllCookiesForUrlAction
, cookie_monster
, url
, callback
) {
700 cookie_monster
->GetAllCookiesForURLAsync(url
, callback
->AsCallback());
703 ACTION_P(PushCallbackAction
, callback_vector
) {
704 callback_vector
->push(arg1
);
707 ACTION_P2(DeleteSessionCookiesAction
, cookie_monster
, callback
) {
708 cookie_monster
->DeleteSessionCookiesAsync(callback
->AsCallback());
713 // This test suite verifies the task deferral behaviour of the CookieMonster.
714 // Specifically, for each asynchronous method, verify that:
715 // 1. invoking it on an uninitialized cookie store causes the store to begin
716 // chain-loading its backing data or loading data for a specific domain key
718 // 2. The initial invocation does not complete until the loading completes.
719 // 3. Invocations after the loading has completed complete immediately.
720 class DeferredCookieTaskTest
: public CookieMonsterTest
{
722 DeferredCookieTaskTest() {
723 persistent_store_
= new NewMockPersistentCookieStore();
724 cookie_monster_
= new CookieMonster(persistent_store_
.get(), NULL
);
727 // Defines a cookie to be returned from PersistentCookieStore::Load
728 void DeclareLoadedCookie(const std::string
& key
,
729 const std::string
& cookie_line
,
730 const base::Time
& creation_time
) {
731 AddCookieToList(key
, cookie_line
, creation_time
, &loaded_cookies_
);
734 // Runs the message loop, waiting until PersistentCookieStore::Load is called.
735 // Call CompleteLoadingAndWait to cause the load to complete.
736 void WaitForLoadCall() {
739 // Verify that PeristentStore::Load was called.
740 testing::Mock::VerifyAndClear(persistent_store_
.get());
743 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
744 // and PersistentCookieStore::Load completion callback and waits
745 // until the message loop is quit.
746 void CompleteLoadingAndWait() {
747 while (!loaded_for_key_callbacks_
.empty()) {
748 loaded_for_key_callbacks_
.front().Run(loaded_cookies_
);
749 loaded_cookies_
.clear();
750 loaded_for_key_callbacks_
.pop();
753 loaded_callback_
.Run(loaded_cookies_
);
757 // Performs the provided action, expecting it to cause a call to
758 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call
760 void BeginWith(testing::Action
<void(void)> action
) {
761 EXPECT_CALL(*this, Begin()).WillOnce(action
);
766 void BeginWithForDomainKey(std::string key
,
767 testing::Action
<void(void)> action
) {
768 EXPECT_CALL(*this, Begin()).WillOnce(action
);
770 ExpectLoadForKeyCall(key
, false);
774 // Declares an expectation that PersistentCookieStore::Load will be called,
775 // saving the provided callback and sending a quit to the message loop.
776 void ExpectLoadCall() {
777 EXPECT_CALL(*persistent_store_
.get(), Load(testing::_
))
778 .WillOnce(testing::DoAll(testing::SaveArg
<0>(&loaded_callback_
),
779 QuitCurrentMessageLoop()));
782 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
783 // will be called, saving the provided callback and sending a quit to the
785 void ExpectLoadForKeyCall(std::string key
, bool quit_queue
) {
787 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
789 testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_
),
790 QuitCurrentMessageLoop()));
792 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
793 .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_
));
796 // Invokes the initial action.
797 MOCK_METHOD0(Begin
, void(void));
799 // Returns the CookieMonster instance under test.
800 CookieMonster
& cookie_monster() { return *cookie_monster_
.get(); }
803 // Declares that mock expectations in this test suite are strictly ordered.
804 testing::InSequence in_sequence_
;
805 // Holds cookies to be returned from PersistentCookieStore::Load or
806 // PersistentCookieStore::LoadCookiesForKey.
807 std::vector
<CanonicalCookie
*> loaded_cookies_
;
808 // Stores the callback passed from the CookieMonster to the
809 // PersistentCookieStore::Load
810 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_
;
811 // Stores the callback passed from the CookieMonster to the
812 // PersistentCookieStore::LoadCookiesForKey
813 std::queue
<CookieMonster::PersistentCookieStore::LoadedCallback
>
814 loaded_for_key_callbacks_
;
816 // Stores the CookieMonster under test.
817 scoped_refptr
<CookieMonster
> cookie_monster_
;
818 // Stores the mock PersistentCookieStore.
819 scoped_refptr
<NewMockPersistentCookieStore
> persistent_store_
;
822 TEST_F(DeferredCookieTaskTest
, DeferredGetCookies
) {
823 DeclareLoadedCookie("www.google.izzle",
824 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
825 Time::Now() + TimeDelta::FromDays(3));
827 MockGetCookiesCallback get_cookies_callback
;
829 BeginWithForDomainKey(
831 GetCookiesAction(&cookie_monster(), url_google_
, &get_cookies_callback
));
835 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
836 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_
,
837 &get_cookies_callback
));
838 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
839 .WillOnce(QuitCurrentMessageLoop());
841 CompleteLoadingAndWait();
844 TEST_F(DeferredCookieTaskTest
, DeferredSetCookie
) {
845 MockSetCookiesCallback set_cookies_callback
;
847 BeginWithForDomainKey("google.izzle",
848 SetCookieAction(&cookie_monster(), url_google_
, "A=B",
849 &set_cookies_callback
));
853 EXPECT_CALL(set_cookies_callback
, Invoke(true))
854 .WillOnce(SetCookieAction(&cookie_monster(), url_google_
, "X=Y",
855 &set_cookies_callback
));
856 EXPECT_CALL(set_cookies_callback
, Invoke(true))
857 .WillOnce(QuitCurrentMessageLoop());
859 CompleteLoadingAndWait();
862 TEST_F(DeferredCookieTaskTest
, DeferredSetAllCookies
) {
863 MockSetCookiesCallback set_cookies_callback
;
865 list
.push_back(CanonicalCookie(url_google_
, "A", "B", "google.izzle", "/",
866 base::Time::Now(), base::Time(), base::Time(),
867 false, true, false, COOKIE_PRIORITY_DEFAULT
));
868 list
.push_back(CanonicalCookie(url_google_
, "C", "D", "google.izzle", "/",
869 base::Time::Now(), base::Time(), base::Time(),
870 false, true, false, COOKIE_PRIORITY_DEFAULT
));
873 SetAllCookiesAction(&cookie_monster(), list
, &set_cookies_callback
));
877 EXPECT_CALL(set_cookies_callback
, Invoke(true))
879 SetAllCookiesAction(&cookie_monster(), list
, &set_cookies_callback
));
880 EXPECT_CALL(set_cookies_callback
, Invoke(true))
881 .WillOnce(QuitCurrentMessageLoop());
883 CompleteLoadingAndWait();
886 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCookie
) {
887 MockClosure delete_cookie_callback
;
889 BeginWithForDomainKey("google.izzle",
890 DeleteCookieAction(&cookie_monster(), url_google_
, "A",
891 &delete_cookie_callback
));
895 EXPECT_CALL(delete_cookie_callback
, Invoke())
896 .WillOnce(DeleteCookieAction(&cookie_monster(), url_google_
, "X",
897 &delete_cookie_callback
));
898 EXPECT_CALL(delete_cookie_callback
, Invoke())
899 .WillOnce(QuitCurrentMessageLoop());
901 CompleteLoadingAndWait();
904 TEST_F(DeferredCookieTaskTest
, DeferredSetCookieWithDetails
) {
905 MockSetCookiesCallback set_cookies_callback
;
907 CookiesInputInfo cookie_info
= {url_google_foo_
,
916 COOKIE_PRIORITY_DEFAULT
};
917 BeginWithForDomainKey(
918 "google.izzle", SetCookieWithDetailsAction(&cookie_monster(), cookie_info
,
919 &set_cookies_callback
));
923 CookiesInputInfo cookie_info_exp
= {url_google_foo_
,
932 COOKIE_PRIORITY_DEFAULT
};
933 EXPECT_CALL(set_cookies_callback
, Invoke(true))
934 .WillOnce(SetCookieWithDetailsAction(&cookie_monster(), cookie_info_exp
,
935 &set_cookies_callback
));
936 EXPECT_CALL(set_cookies_callback
, Invoke(true))
937 .WillOnce(QuitCurrentMessageLoop());
939 CompleteLoadingAndWait();
942 TEST_F(DeferredCookieTaskTest
, DeferredGetAllCookies
) {
943 DeclareLoadedCookie("www.google.izzle",
944 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
945 Time::Now() + TimeDelta::FromDays(3));
947 MockGetCookieListCallback get_cookie_list_callback
;
949 BeginWith(GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback
));
953 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
955 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback
));
956 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
957 .WillOnce(QuitCurrentMessageLoop());
959 CompleteLoadingAndWait();
962 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlCookies
) {
963 DeclareLoadedCookie("www.google.izzle",
964 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
965 Time::Now() + TimeDelta::FromDays(3));
967 MockGetCookieListCallback get_cookie_list_callback
;
969 BeginWithForDomainKey(
970 "google.izzle", GetAllCookiesForUrlAction(&cookie_monster(), url_google_
,
971 &get_cookie_list_callback
));
975 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
976 .WillOnce(GetAllCookiesForUrlAction(&cookie_monster(), url_google_
,
977 &get_cookie_list_callback
));
978 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
979 .WillOnce(QuitCurrentMessageLoop());
981 CompleteLoadingAndWait();
984 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlWithOptionsCookies
) {
985 DeclareLoadedCookie("www.google.izzle",
986 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
987 Time::Now() + TimeDelta::FromDays(3));
989 MockGetCookieListCallback get_cookie_list_callback
;
991 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
992 &cookie_monster(), url_google_
,
993 &get_cookie_list_callback
));
997 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
998 .WillOnce(GetAllCookiesForUrlWithOptionsAction(
999 &cookie_monster(), url_google_
, &get_cookie_list_callback
));
1000 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
1001 .WillOnce(QuitCurrentMessageLoop());
1003 CompleteLoadingAndWait();
1006 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCookies
) {
1007 MockDeleteCallback delete_callback
;
1009 BeginWith(DeleteAllAction(&cookie_monster(), &delete_callback
));
1013 EXPECT_CALL(delete_callback
, Invoke(false))
1014 .WillOnce(DeleteAllAction(&cookie_monster(), &delete_callback
));
1015 EXPECT_CALL(delete_callback
, Invoke(false))
1016 .WillOnce(QuitCurrentMessageLoop());
1018 CompleteLoadingAndWait();
1021 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCreatedBetweenCookies
) {
1022 MockDeleteCallback delete_callback
;
1024 BeginWith(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
1025 base::Time::Now(), &delete_callback
));
1029 EXPECT_CALL(delete_callback
, Invoke(false))
1030 .WillOnce(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
1033 EXPECT_CALL(delete_callback
, Invoke(false))
1034 .WillOnce(QuitCurrentMessageLoop());
1036 CompleteLoadingAndWait();
1039 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllForHostCookies
) {
1040 MockDeleteCallback delete_callback
;
1042 BeginWithForDomainKey(
1044 DeleteAllForHostAction(&cookie_monster(), url_google_
, &delete_callback
));
1048 EXPECT_CALL(delete_callback
, Invoke(false))
1049 .WillOnce(DeleteAllForHostAction(&cookie_monster(), url_google_
,
1051 EXPECT_CALL(delete_callback
, Invoke(false))
1052 .WillOnce(QuitCurrentMessageLoop());
1054 CompleteLoadingAndWait();
1057 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCanonicalCookie
) {
1058 std::vector
<CanonicalCookie
*> cookies
;
1059 CanonicalCookie cookie
=
1060 BuildCanonicalCookie("www.google.com", "X=1; path=/", base::Time::Now());
1062 MockDeleteCookieCallback delete_cookie_callback
;
1064 BeginWith(DeleteCanonicalCookieAction(&cookie_monster(), cookie
,
1065 &delete_cookie_callback
));
1069 EXPECT_CALL(delete_cookie_callback
, Invoke(false))
1070 .WillOnce(DeleteCanonicalCookieAction(&cookie_monster(), cookie
,
1071 &delete_cookie_callback
));
1072 EXPECT_CALL(delete_cookie_callback
, Invoke(false))
1073 .WillOnce(QuitCurrentMessageLoop());
1075 CompleteLoadingAndWait();
1078 TEST_F(DeferredCookieTaskTest
, DeferredDeleteSessionCookies
) {
1079 MockDeleteCallback delete_callback
;
1081 BeginWith(DeleteSessionCookiesAction(&cookie_monster(), &delete_callback
));
1085 EXPECT_CALL(delete_callback
, Invoke(false))
1087 DeleteSessionCookiesAction(&cookie_monster(), &delete_callback
));
1088 EXPECT_CALL(delete_callback
, Invoke(false))
1089 .WillOnce(QuitCurrentMessageLoop());
1091 CompleteLoadingAndWait();
1094 // Verify that a series of queued tasks are executed in order upon loading of
1095 // the backing store and that new tasks received while the queued tasks are
1096 // being dispatched go to the end of the queue.
1097 TEST_F(DeferredCookieTaskTest
, DeferredTaskOrder
) {
1098 DeclareLoadedCookie("www.google.izzle",
1099 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1100 Time::Now() + TimeDelta::FromDays(3));
1102 MockGetCookiesCallback get_cookies_callback
;
1103 MockSetCookiesCallback set_cookies_callback
;
1104 MockGetCookiesCallback get_cookies_callback_deferred
;
1106 EXPECT_CALL(*this, Begin())
1107 .WillOnce(testing::DoAll(GetCookiesAction(&cookie_monster(), url_google_
,
1108 &get_cookies_callback
),
1109 SetCookieAction(&cookie_monster(), url_google_
,
1110 "A=B", &set_cookies_callback
)));
1112 ExpectLoadForKeyCall("google.izzle", false);
1116 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
1117 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_
,
1118 &get_cookies_callback_deferred
));
1119 EXPECT_CALL(set_cookies_callback
, Invoke(true));
1120 EXPECT_CALL(get_cookies_callback_deferred
, Invoke("A=B; X=1"))
1121 .WillOnce(QuitCurrentMessageLoop());
1123 CompleteLoadingAndWait();
1126 TEST_F(CookieMonsterTest
, TestCookieDeleteAll
) {
1127 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1128 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1129 CookieOptions options
;
1130 options
.set_include_httponly();
1132 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
1133 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1136 SetCookieWithOptions(cm
.get(), url_google_
, "C=D; httponly", options
));
1137 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1139 EXPECT_EQ(2, DeleteAll(cm
.get()));
1140 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1141 EXPECT_EQ(0u, store
->commands().size());
1143 // Create a persistent cookie.
1144 EXPECT_TRUE(SetCookie(
1145 cm
.get(), url_google_
,
1146 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1147 ASSERT_EQ(1u, store
->commands().size());
1148 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1150 EXPECT_EQ(1, DeleteAll(cm
.get())); // sync_to_store = true.
1151 ASSERT_EQ(2u, store
->commands().size());
1152 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1154 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1157 TEST_F(CookieMonsterTest
, TestCookieDeleteAllCreatedBetweenTimestamps
) {
1158 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1159 Time now
= Time::Now();
1161 // Nothing has been added so nothing should be deleted.
1162 EXPECT_EQ(0, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99),
1165 // Create 3 cookies with creation date of today, yesterday and the day before.
1166 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-0=Now", now
));
1167 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-1=Yesterday",
1168 now
- TimeDelta::FromDays(1)));
1169 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-2=DayBefore",
1170 now
- TimeDelta::FromDays(2)));
1171 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-3=ThreeDays",
1172 now
- TimeDelta::FromDays(3)));
1173 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-7=LastWeek",
1174 now
- TimeDelta::FromDays(7)));
1176 // Try to delete threedays and the daybefore.
1177 EXPECT_EQ(2, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(3),
1178 now
- TimeDelta::FromDays(1)));
1180 // Try to delete yesterday, also make sure that delete_end is not
1183 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(2), now
));
1185 // Make sure the delete_begin is inclusive.
1187 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(7), now
));
1189 // Delete the last (now) item.
1190 EXPECT_EQ(1, DeleteAllCreatedBetween(cm
.get(), Time(), Time()));
1192 // Really make sure everything is gone.
1193 EXPECT_EQ(0, DeleteAll(cm
.get()));
1196 static const int kAccessDelayMs
= kLastAccessThresholdMilliseconds
+ 20;
1198 TEST_F(CookieMonsterTest
, TestLastAccess
) {
1199 scoped_refptr
<CookieMonster
> cm(
1200 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1202 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1203 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1205 // Reading the cookie again immediately shouldn't update the access date,
1206 // since we're inside the threshold.
1207 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1208 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1210 // Reading after a short wait should update the access date.
1211 base::PlatformThread::Sleep(
1212 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1213 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1214 EXPECT_FALSE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1217 TEST_F(CookieMonsterTest
, TestHostGarbageCollection
) {
1218 TestHostGarbageCollectHelper();
1221 TEST_F(CookieMonsterTest
, TestPriorityAwareGarbageCollection
) {
1222 TestPriorityAwareGarbageCollectHelper();
1225 TEST_F(CookieMonsterTest
, TestDeleteSingleCookie
) {
1226 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1228 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1229 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1230 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1231 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1233 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1234 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1236 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1237 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1240 TEST_F(CookieMonsterTest
, SetCookieableSchemes
) {
1241 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1242 scoped_refptr
<CookieMonster
> cm_foo(new CookieMonster(NULL
, NULL
));
1244 // Only cm_foo should allow foo:// cookies.
1245 const char* const kSchemes
[] = {"foo"};
1246 cm_foo
->SetCookieableSchemes(kSchemes
, 1);
1248 GURL
foo_url("foo://host/path");
1249 GURL
http_url("http://host/path");
1251 EXPECT_TRUE(SetCookie(cm
.get(), http_url
, "x=1"));
1252 EXPECT_FALSE(SetCookie(cm
.get(), foo_url
, "x=1"));
1253 EXPECT_TRUE(SetCookie(cm_foo
.get(), foo_url
, "x=1"));
1254 EXPECT_FALSE(SetCookie(cm_foo
.get(), http_url
, "x=1"));
1257 TEST_F(CookieMonsterTest
, GetAllCookiesForURL
) {
1258 scoped_refptr
<CookieMonster
> cm(
1259 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1261 // Create an httponly cookie.
1262 CookieOptions options
;
1263 options
.set_include_httponly();
1266 SetCookieWithOptions(cm
.get(), url_google_
, "A=B; httponly", options
));
1267 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
,
1268 "C=D; domain=.google.izzle", options
));
1269 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_secure_
,
1270 "E=F; domain=.google.izzle; secure",
1273 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1275 base::PlatformThread::Sleep(
1276 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1278 // Check cookies for url.
1279 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
1280 CookieList::iterator it
= cookies
.begin();
1282 ASSERT_TRUE(it
!= cookies
.end());
1283 EXPECT_EQ("www.google.izzle", it
->Domain());
1284 EXPECT_EQ("A", it
->Name());
1286 ASSERT_TRUE(++it
!= cookies
.end());
1287 EXPECT_EQ(".google.izzle", it
->Domain());
1288 EXPECT_EQ("C", it
->Name());
1290 ASSERT_TRUE(++it
== cookies
.end());
1292 // Check cookies for url excluding http-only cookies.
1294 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, CookieOptions());
1295 it
= cookies
.begin();
1297 ASSERT_TRUE(it
!= cookies
.end());
1298 EXPECT_EQ(".google.izzle", it
->Domain());
1299 EXPECT_EQ("C", it
->Name());
1301 ASSERT_TRUE(++it
== cookies
.end());
1303 // Test secure cookies.
1304 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1305 it
= cookies
.begin();
1307 ASSERT_TRUE(it
!= cookies
.end());
1308 EXPECT_EQ("www.google.izzle", it
->Domain());
1309 EXPECT_EQ("A", it
->Name());
1311 ASSERT_TRUE(++it
!= cookies
.end());
1312 EXPECT_EQ(".google.izzle", it
->Domain());
1313 EXPECT_EQ("C", it
->Name());
1315 ASSERT_TRUE(++it
!= cookies
.end());
1316 EXPECT_EQ(".google.izzle", it
->Domain());
1317 EXPECT_EQ("E", it
->Name());
1319 ASSERT_TRUE(++it
== cookies
.end());
1321 // Reading after a short wait should not update the access date.
1322 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1325 TEST_F(CookieMonsterTest
, GetAllCookiesForURLPathMatching
) {
1326 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1327 CookieOptions options
;
1329 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_foo_
, "A=B; path=/foo;",
1331 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_bar_
, "C=D; path=/bar;",
1333 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "E=F;", options
));
1335 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1336 CookieList::iterator it
= cookies
.begin();
1338 ASSERT_TRUE(it
!= cookies
.end());
1339 EXPECT_EQ("A", it
->Name());
1340 EXPECT_EQ("/foo", it
->Path());
1342 ASSERT_TRUE(++it
!= cookies
.end());
1343 EXPECT_EQ("E", it
->Name());
1344 EXPECT_EQ("/", it
->Path());
1346 ASSERT_TRUE(++it
== cookies
.end());
1348 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1349 it
= cookies
.begin();
1351 ASSERT_TRUE(it
!= cookies
.end());
1352 EXPECT_EQ("C", it
->Name());
1353 EXPECT_EQ("/bar", it
->Path());
1355 ASSERT_TRUE(++it
!= cookies
.end());
1356 EXPECT_EQ("E", it
->Name());
1357 EXPECT_EQ("/", it
->Path());
1359 ASSERT_TRUE(++it
== cookies
.end());
1362 TEST_F(CookieMonsterTest
, DeleteCookieByName
) {
1363 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1365 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A1; path=/"));
1366 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A2; path=/foo"));
1367 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A3; path=/bar"));
1368 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B1; path=/"));
1369 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B2; path=/foo"));
1370 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B3; path=/bar"));
1372 DeleteCookie(cm
.get(), GURL(std::string(kUrlGoogle
) + "/foo/bar"), "A");
1374 CookieList cookies
= GetAllCookies(cm
.get());
1375 size_t expected_size
= 4;
1376 EXPECT_EQ(expected_size
, cookies
.size());
1377 for (CookieList::iterator it
= cookies
.begin(); it
!= cookies
.end(); ++it
) {
1378 EXPECT_NE("A1", it
->Value());
1379 EXPECT_NE("A2", it
->Value());
1383 TEST_F(CookieMonsterTest
, ImportCookiesFromCookieMonster
) {
1384 scoped_refptr
<CookieMonster
> cm_1(new CookieMonster(NULL
, NULL
));
1385 CookieOptions options
;
1387 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_foo_
,
1388 "A1=B; path=/foo;", options
));
1389 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_bar_
,
1390 "A2=D; path=/bar;", options
));
1391 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_
, "A3=F;", options
));
1393 CookieList cookies_1
= GetAllCookies(cm_1
.get());
1394 scoped_refptr
<CookieMonster
> cm_2(new CookieMonster(NULL
, NULL
));
1395 ASSERT_TRUE(cm_2
->ImportCookies(cookies_1
));
1396 CookieList cookies_2
= GetAllCookies(cm_2
.get());
1398 size_t expected_size
= 3;
1399 EXPECT_EQ(expected_size
, cookies_2
.size());
1401 CookieList::iterator it
= cookies_2
.begin();
1403 ASSERT_TRUE(it
!= cookies_2
.end());
1404 EXPECT_EQ("A1", it
->Name());
1405 EXPECT_EQ("/foo", it
->Path());
1407 ASSERT_TRUE(++it
!= cookies_2
.end());
1408 EXPECT_EQ("A2", it
->Name());
1409 EXPECT_EQ("/bar", it
->Path());
1411 ASSERT_TRUE(++it
!= cookies_2
.end());
1412 EXPECT_EQ("A3", it
->Name());
1413 EXPECT_EQ("/", it
->Path());
1416 // Tests importing from a persistent cookie store that contains duplicate
1417 // equivalent cookies. This situation should be handled by removing the
1418 // duplicate cookie (both from the in-memory cache, and from the backing store).
1420 // This is a regression test for: http://crbug.com/17855.
1421 TEST_F(CookieMonsterTest
, DontImportDuplicateCookies
) {
1422 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1424 // We will fill some initial cookies into the PersistentCookieStore,
1425 // to simulate a database with 4 duplicates. Note that we need to
1426 // be careful not to have any duplicate creation times at all (as it's a
1427 // violation of a CookieMonster invariant) even if Time::Now() doesn't
1428 // move between calls.
1429 std::vector
<CanonicalCookie
*> initial_cookies
;
1431 // Insert 4 cookies with name "X" on path "/", with varying creation
1432 // dates. We expect only the most recent one to be preserved following
1435 AddCookieToList("www.google.com",
1436 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1437 Time::Now() + TimeDelta::FromDays(3), &initial_cookies
);
1439 AddCookieToList("www.google.com",
1440 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1441 Time::Now() + TimeDelta::FromDays(1), &initial_cookies
);
1443 // ===> This one is the WINNER (biggest creation time). <====
1444 AddCookieToList("www.google.com",
1445 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1446 Time::Now() + TimeDelta::FromDays(4), &initial_cookies
);
1448 AddCookieToList("www.google.com",
1449 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1450 Time::Now(), &initial_cookies
);
1452 // Insert 2 cookies with name "X" on path "/2", with varying creation
1453 // dates. We expect only the most recent one to be preserved the import.
1455 // ===> This one is the WINNER (biggest creation time). <====
1456 AddCookieToList("www.google.com",
1457 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1458 Time::Now() + TimeDelta::FromDays(9), &initial_cookies
);
1460 AddCookieToList("www.google.com",
1461 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1462 Time::Now() + TimeDelta::FromDays(2), &initial_cookies
);
1464 // Insert 1 cookie with name "Y" on path "/".
1465 AddCookieToList("www.google.com",
1466 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1467 Time::Now() + TimeDelta::FromDays(10), &initial_cookies
);
1469 // Inject our initial cookies into the mock PersistentCookieStore.
1470 store
->SetLoadExpectation(true, initial_cookies
);
1472 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1474 // Verify that duplicates were not imported for path "/".
1475 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1476 EXPECT_EQ("X=3; Y=a", GetCookies(cm
.get(), GURL("http://www.google.com/")));
1478 // Verify that same-named cookie on a different path ("/x2") didn't get
1480 EXPECT_EQ("X=a1; X=3; Y=a",
1481 GetCookies(cm
.get(), GURL("http://www.google.com/2/x")));
1483 // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1484 ASSERT_EQ(4u, store
->commands().size());
1485 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[0].type
);
1486 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1487 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[2].type
);
1488 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
1491 // Tests importing from a persistent cookie store that contains cookies
1492 // with duplicate creation times. This situation should be handled by
1493 // dropping the cookies before insertion/visibility to user.
1495 // This is a regression test for: http://crbug.com/43188.
1496 TEST_F(CookieMonsterTest
, DontImportDuplicateCreationTimes
) {
1497 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1499 Time
now(Time::Now());
1500 Time
earlier(now
- TimeDelta::FromDays(1));
1502 // Insert 8 cookies, four with the current time as creation times, and
1503 // four with the earlier time as creation times. We should only get
1504 // two cookies remaining, but which two (other than that there should
1505 // be one from each set) will be random.
1506 std::vector
<CanonicalCookie
*> initial_cookies
;
1507 AddCookieToList("www.google.com", "X=1; path=/", now
, &initial_cookies
);
1508 AddCookieToList("www.google.com", "X=2; path=/", now
, &initial_cookies
);
1509 AddCookieToList("www.google.com", "X=3; path=/", now
, &initial_cookies
);
1510 AddCookieToList("www.google.com", "X=4; path=/", now
, &initial_cookies
);
1512 AddCookieToList("www.google.com", "Y=1; path=/", earlier
, &initial_cookies
);
1513 AddCookieToList("www.google.com", "Y=2; path=/", earlier
, &initial_cookies
);
1514 AddCookieToList("www.google.com", "Y=3; path=/", earlier
, &initial_cookies
);
1515 AddCookieToList("www.google.com", "Y=4; path=/", earlier
, &initial_cookies
);
1517 // Inject our initial cookies into the mock PersistentCookieStore.
1518 store
->SetLoadExpectation(true, initial_cookies
);
1520 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1522 CookieList
list(GetAllCookies(cm
.get()));
1523 EXPECT_EQ(2U, list
.size());
1524 // Confirm that we have one of each.
1525 std::string
name1(list
[0].Name());
1526 std::string
name2(list
[1].Name());
1527 EXPECT_TRUE(name1
== "X" || name2
== "X");
1528 EXPECT_TRUE(name1
== "Y" || name2
== "Y");
1529 EXPECT_NE(name1
, name2
);
1532 TEST_F(CookieMonsterTest
, CookieMonsterDelegate
) {
1533 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1534 scoped_refptr
<MockCookieMonsterDelegate
> delegate(
1535 new MockCookieMonsterDelegate
);
1536 scoped_refptr
<CookieMonster
> cm(
1537 new CookieMonster(store
.get(), delegate
.get()));
1539 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1540 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1541 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1542 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1543 ASSERT_EQ(3u, delegate
->changes().size());
1544 EXPECT_FALSE(delegate
->changes()[0].second
);
1545 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1546 EXPECT_EQ("A", delegate
->changes()[0].first
.Name());
1547 EXPECT_EQ("B", delegate
->changes()[0].first
.Value());
1548 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1549 EXPECT_FALSE(delegate
->changes()[1].second
);
1550 EXPECT_EQ("C", delegate
->changes()[1].first
.Name());
1551 EXPECT_EQ("D", delegate
->changes()[1].first
.Value());
1552 EXPECT_EQ(url_google_
.host(), delegate
->changes()[2].first
.Domain());
1553 EXPECT_FALSE(delegate
->changes()[2].second
);
1554 EXPECT_EQ("E", delegate
->changes()[2].first
.Name());
1555 EXPECT_EQ("F", delegate
->changes()[2].first
.Value());
1558 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1559 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1560 ASSERT_EQ(1u, delegate
->changes().size());
1561 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1562 EXPECT_TRUE(delegate
->changes()[0].second
);
1563 EXPECT_EQ("C", delegate
->changes()[0].first
.Name());
1564 EXPECT_EQ("D", delegate
->changes()[0].first
.Value());
1567 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1568 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1569 EXPECT_EQ(0u, delegate
->changes().size());
1571 // Insert a cookie "a" for path "/path1"
1572 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
1573 "a=val1; path=/path1; "
1574 "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1575 ASSERT_EQ(1u, store
->commands().size());
1576 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1577 ASSERT_EQ(1u, delegate
->changes().size());
1578 EXPECT_FALSE(delegate
->changes()[0].second
);
1579 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1580 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1581 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1584 // Insert a cookie "a" for path "/path1", that is httponly. This should
1585 // overwrite the non-http-only version.
1586 CookieOptions allow_httponly
;
1587 allow_httponly
.set_include_httponly();
1588 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
,
1589 "a=val2; path=/path1; httponly; "
1590 "expires=Mon, 18-Apr-22 22:50:14 GMT",
1592 ASSERT_EQ(3u, store
->commands().size());
1593 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1594 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
1595 ASSERT_EQ(2u, delegate
->changes().size());
1596 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1597 EXPECT_TRUE(delegate
->changes()[0].second
);
1598 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1599 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1600 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1601 EXPECT_FALSE(delegate
->changes()[1].second
);
1602 EXPECT_EQ("a", delegate
->changes()[1].first
.Name());
1603 EXPECT_EQ("val2", delegate
->changes()[1].first
.Value());
1607 TEST_F(CookieMonsterTest
, SetCookieWithDetails
) {
1608 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1610 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A", "B",
1611 std::string(), "/foo", base::Time(), false,
1612 false, false, COOKIE_PRIORITY_DEFAULT
));
1613 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_bar_
, "C", "D",
1614 "google.izzle", "/bar", base::Time(), false,
1615 true, false, COOKIE_PRIORITY_DEFAULT
));
1616 EXPECT_TRUE(SetCookieWithDetails(
1617 cm
.get(), url_google_
, "E", "F", std::string(), std::string(),
1618 base::Time(), true, false, false, COOKIE_PRIORITY_DEFAULT
));
1620 // Test that malformed attributes fail to set the cookie.
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(cm
.get(), url_google_foo_
, "A=", "B",
1628 std::string(), "/foo", base::Time(), false,
1629 false, false, COOKIE_PRIORITY_DEFAULT
));
1630 EXPECT_FALSE(SetCookieWithDetails(
1631 cm
.get(), url_google_foo_
, "A", "B", "google.ozzzzzzle", "foo",
1632 base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
1633 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A=", "B",
1634 std::string(), "foo", base::Time(), false,
1635 false, false, COOKIE_PRIORITY_DEFAULT
));
1637 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1638 CookieList::iterator it
= cookies
.begin();
1640 ASSERT_TRUE(it
!= cookies
.end());
1641 EXPECT_EQ("A", it
->Name());
1642 EXPECT_EQ("B", it
->Value());
1643 EXPECT_EQ("www.google.izzle", it
->Domain());
1644 EXPECT_EQ("/foo", it
->Path());
1645 EXPECT_FALSE(it
->IsPersistent());
1646 EXPECT_FALSE(it
->IsSecure());
1647 EXPECT_FALSE(it
->IsHttpOnly());
1649 ASSERT_TRUE(++it
== cookies
.end());
1651 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1652 it
= cookies
.begin();
1654 ASSERT_TRUE(it
!= cookies
.end());
1655 EXPECT_EQ("C", it
->Name());
1656 EXPECT_EQ("D", it
->Value());
1657 EXPECT_EQ(".google.izzle", it
->Domain());
1658 EXPECT_EQ("/bar", it
->Path());
1659 EXPECT_FALSE(it
->IsSecure());
1660 EXPECT_TRUE(it
->IsHttpOnly());
1662 ASSERT_TRUE(++it
== cookies
.end());
1664 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1665 it
= cookies
.begin();
1667 ASSERT_TRUE(it
!= cookies
.end());
1668 EXPECT_EQ("E", it
->Name());
1669 EXPECT_EQ("F", it
->Value());
1670 EXPECT_EQ("/", it
->Path());
1671 EXPECT_EQ("www.google.izzle", it
->Domain());
1672 EXPECT_TRUE(it
->IsSecure());
1673 EXPECT_FALSE(it
->IsHttpOnly());
1675 ASSERT_TRUE(++it
== cookies
.end());
1678 TEST_F(CookieMonsterTest
, DeleteAllForHost
) {
1679 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1682 // * Non-secure URL, mid-level (http://w.c.b.a)
1683 // * Secure URL, mid-level (https://w.c.b.a)
1684 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1685 // All three tests should nuke only the midlevel host cookie,
1686 // the http_only cookie, the host secure cookie, and the two host
1687 // path cookies. http_only, secure, and paths are ignored by
1688 // this call, and domain cookies arent touched.
1689 PopulateCmForDeleteAllForHost(cm
);
1690 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1691 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1692 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1693 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1694 EXPECT_EQ("dom_1=X; host_1=X",
1695 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1697 "dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1698 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1699 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1700 std::string("/dir1/dir2/xxx"))));
1702 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2
)));
1703 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1705 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1706 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1707 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1708 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1709 EXPECT_EQ("dom_1=X; host_1=X",
1710 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1711 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1712 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1713 std::string("/dir1/dir2/xxx"))));
1715 PopulateCmForDeleteAllForHost(cm
);
1716 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1717 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1719 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1720 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1721 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1722 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1723 EXPECT_EQ("dom_1=X; host_1=X",
1724 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1725 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1726 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1727 std::string("/dir1/dir2/xxx"))));
1729 PopulateCmForDeleteAllForHost(cm
);
1730 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1731 std::string("/dir1/xxx"))));
1732 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1734 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1735 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1736 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1737 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1738 EXPECT_EQ("dom_1=X; host_1=X",
1739 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1740 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1741 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1742 std::string("/dir1/dir2/xxx"))));
1745 TEST_F(CookieMonsterTest
, UniqueCreationTime
) {
1746 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1747 CookieOptions options
;
1749 // Add in three cookies through every public interface to the
1750 // CookieMonster and confirm that none of them have duplicate
1753 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1754 // are not included as they aren't going to be public for very much
1757 // SetCookie, SetCookieWithOptions, SetCookieWithDetails
1759 SetCookie(cm
.get(), url_google_
, "SetCookie1=A");
1760 SetCookie(cm
.get(), url_google_
, "SetCookie2=A");
1761 SetCookie(cm
.get(), url_google_
, "SetCookie3=A");
1763 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions1=A",
1765 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions2=A",
1767 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions3=A",
1770 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails1", "A",
1771 ".google.com", "/", Time(), false, false, false,
1772 COOKIE_PRIORITY_DEFAULT
);
1773 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails2", "A",
1774 ".google.com", "/", Time(), false, false, false,
1775 COOKIE_PRIORITY_DEFAULT
);
1776 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails3", "A",
1777 ".google.com", "/", Time(), false, false, false,
1778 COOKIE_PRIORITY_DEFAULT
);
1781 CookieList
cookie_list(GetAllCookies(cm
.get()));
1782 typedef std::map
<int64
, CanonicalCookie
> TimeCookieMap
;
1783 TimeCookieMap check_map
;
1784 for (CookieList::const_iterator it
= cookie_list
.begin();
1785 it
!= cookie_list
.end(); it
++) {
1786 const int64 creation_date
= it
->CreationDate().ToInternalValue();
1787 TimeCookieMap::const_iterator
existing_cookie_it(
1788 check_map
.find(creation_date
));
1789 EXPECT_TRUE(existing_cookie_it
== check_map
.end())
1790 << "Cookie " << it
->Name() << " has same creation date ("
1791 << it
->CreationDate().ToInternalValue()
1792 << ") as previously entered cookie "
1793 << existing_cookie_it
->second
.Name();
1795 if (existing_cookie_it
== check_map
.end()) {
1797 TimeCookieMap::value_type(it
->CreationDate().ToInternalValue(), *it
));
1802 // Mainly a test of GetEffectiveDomain, or more specifically, of the
1803 // expected behavior of GetEffectiveDomain within the CookieMonster.
1804 TEST_F(CookieMonsterTest
, GetKey
) {
1805 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1807 // This test is really only interesting if GetKey() actually does something.
1808 EXPECT_EQ("google.com", cm
->GetKey("www.google.com"));
1809 EXPECT_EQ("google.izzie", cm
->GetKey("www.google.izzie"));
1810 EXPECT_EQ("google.izzie", cm
->GetKey(".google.izzie"));
1811 EXPECT_EQ("bbc.co.uk", cm
->GetKey("bbc.co.uk"));
1812 EXPECT_EQ("bbc.co.uk", cm
->GetKey("a.b.c.d.bbc.co.uk"));
1813 EXPECT_EQ("apple.com", cm
->GetKey("a.b.c.d.apple.com"));
1814 EXPECT_EQ("apple.izzie", cm
->GetKey("a.b.c.d.apple.izzie"));
1816 // Cases where the effective domain is null, so we use the host
1818 EXPECT_EQ("co.uk", cm
->GetKey("co.uk"));
1819 const std::string
extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1820 EXPECT_EQ(extension_name
, cm
->GetKey(extension_name
));
1821 EXPECT_EQ("com", cm
->GetKey("com"));
1822 EXPECT_EQ("hostalias", cm
->GetKey("hostalias"));
1823 EXPECT_EQ("localhost", cm
->GetKey("localhost"));
1826 // Test that cookies transfer from/to the backing store correctly.
1827 TEST_F(CookieMonsterTest
, BackingStoreCommunication
) {
1828 // Store details for cookies transforming through the backing store interface.
1830 base::Time
current(base::Time::Now());
1831 scoped_refptr
<MockSimplePersistentCookieStore
> store(
1832 new MockSimplePersistentCookieStore
);
1833 base::Time new_access_time
;
1834 base::Time
expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1836 const CookiesInputInfo input_info
[] = {
1837 {GURL("http://a.b.google.com"),
1846 COOKIE_PRIORITY_DEFAULT
},
1847 {GURL("https://www.google.com"),
1851 "/path/from/cookie",
1852 expires
+ TimeDelta::FromSeconds(10),
1856 COOKIE_PRIORITY_DEFAULT
},
1857 {GURL("https://google.com"),
1861 "/another/path/to/cookie",
1862 base::Time::Now() + base::TimeDelta::FromSeconds(100),
1866 COOKIE_PRIORITY_DEFAULT
}};
1867 const int INPUT_DELETE
= 1;
1869 // Create new cookies and flush them to the store.
1871 scoped_refptr
<CookieMonster
> cmout(new CookieMonster(store
.get(), NULL
));
1872 for (const CookiesInputInfo
* p
= input_info
;
1873 p
< &input_info
[arraysize(input_info
)]; p
++) {
1874 EXPECT_TRUE(SetCookieWithDetails(cmout
.get(), p
->url
, p
->name
, p
->value
,
1875 p
->domain
, p
->path
, p
->expiration_time
,
1876 p
->secure
, p
->http_only
,
1877 p
->first_party_only
, p
->priority
));
1879 GURL
del_url(input_info
[INPUT_DELETE
]
1880 .url
.Resolve(input_info
[INPUT_DELETE
].path
)
1882 DeleteCookie(cmout
.get(), del_url
, input_info
[INPUT_DELETE
].name
);
1885 // Create a new cookie monster and make sure that everything is correct
1887 scoped_refptr
<CookieMonster
> cmin(new CookieMonster(store
.get(), NULL
));
1888 CookieList
cookies(GetAllCookies(cmin
.get()));
1889 ASSERT_EQ(2u, cookies
.size());
1890 // Ordering is path length, then creation time. So second cookie
1891 // will come first, and we need to swap them.
1892 std::swap(cookies
[0], cookies
[1]);
1893 for (int output_index
= 0; output_index
< 2; output_index
++) {
1894 int input_index
= output_index
* 2;
1895 const CookiesInputInfo
* input
= &input_info
[input_index
];
1896 const CanonicalCookie
* output
= &cookies
[output_index
];
1898 EXPECT_EQ(input
->name
, output
->Name());
1899 EXPECT_EQ(input
->value
, output
->Value());
1900 EXPECT_EQ(input
->url
.host(), output
->Domain());
1901 EXPECT_EQ(input
->path
, output
->Path());
1902 EXPECT_LE(current
.ToInternalValue(),
1903 output
->CreationDate().ToInternalValue());
1904 EXPECT_EQ(input
->secure
, output
->IsSecure());
1905 EXPECT_EQ(input
->http_only
, output
->IsHttpOnly());
1906 EXPECT_EQ(input
->first_party_only
, output
->IsFirstPartyOnly());
1907 EXPECT_TRUE(output
->IsPersistent());
1908 EXPECT_EQ(input
->expiration_time
.ToInternalValue(),
1909 output
->ExpiryDate().ToInternalValue());
1914 TEST_F(CookieMonsterTest
, CookieListOrdering
) {
1915 // Put a random set of cookies into a monster and make sure
1916 // they're returned in the right order.
1917 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1919 SetCookie(cm
.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1"));
1920 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1921 "d=1; domain=b.a.google.com"));
1922 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1923 "a=4; domain=b.a.google.com"));
1924 EXPECT_TRUE(SetCookie(cm
.get(),
1925 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
1926 "e=1; domain=c.b.a.google.com"));
1927 EXPECT_TRUE(SetCookie(cm
.get(),
1928 GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1"));
1929 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://news.bbc.co.uk/midpath/x.html"),
1933 CookieList
cookies(GetAllCookiesForURL(
1934 cm
.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
1935 ASSERT_EQ(5u, cookies
.size());
1936 EXPECT_EQ("d", cookies
[i
++].Name());
1937 EXPECT_EQ("a", cookies
[i
++].Name());
1938 EXPECT_EQ("e", cookies
[i
++].Name());
1939 EXPECT_EQ("b", cookies
[i
++].Name());
1940 EXPECT_EQ("c", cookies
[i
++].Name());
1945 CookieList
cookies(GetAllCookies(cm
.get()));
1946 ASSERT_EQ(6u, cookies
.size());
1947 EXPECT_EQ("d", cookies
[i
++].Name());
1948 EXPECT_EQ("a", cookies
[i
++].Name());
1949 EXPECT_EQ("e", cookies
[i
++].Name());
1950 EXPECT_EQ("g", cookies
[i
++].Name());
1951 EXPECT_EQ("b", cookies
[i
++].Name());
1952 EXPECT_EQ("c", cookies
[i
++].Name());
1956 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
1957 // are somewhat complementary twins. This test is probing for whether
1958 // garbage collection always happens when it should (i.e. that we actually
1959 // get rid of cookies when we should). The perftest is probing for
1960 // whether garbage collection happens when it shouldn't. See comments
1961 // before that test for more details.
1963 // Disabled on Windows, see crbug.com/126095
1965 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers
1967 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers
1970 TEST_F(CookieMonsterTest
, MAYBE_GarbageCollectionTriggers
) {
1971 // First we check to make sure that a whole lot of recent cookies
1972 // doesn't get rid of anything after garbage collection is checked for.
1974 scoped_refptr
<CookieMonster
> cm(
1975 CreateMonsterForGC(CookieMonster::kMaxCookies
* 2));
1976 EXPECT_EQ(CookieMonster::kMaxCookies
* 2, GetAllCookies(cm
.get()).size());
1977 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
1978 EXPECT_EQ(CookieMonster::kMaxCookies
* 2 + 1,
1979 GetAllCookies(cm
.get()).size());
1982 // Now we explore a series of relationships between cookie last access
1983 // time and size of store to make sure we only get rid of cookies when
1984 // we really should.
1985 const struct TestCase
{
1987 size_t num_old_cookies
;
1988 size_t expected_initial_cookies
;
1989 // Indexed by ExpiryAndKeyScheme
1990 size_t expected_cookies_after_set
;
1992 {// A whole lot of recent cookies; gc shouldn't happen.
1993 CookieMonster::kMaxCookies
* 2,
1995 CookieMonster::kMaxCookies
* 2,
1996 CookieMonster::kMaxCookies
* 2 + 1},
1997 {// Some old cookies, but still overflowing max.
1998 CookieMonster::kMaxCookies
* 2,
1999 CookieMonster::kMaxCookies
/ 2,
2000 CookieMonster::kMaxCookies
* 2,
2001 CookieMonster::kMaxCookies
* 2 - CookieMonster::kMaxCookies
/ 2 + 1},
2002 {// Old cookies enough to bring us right down to our purge line.
2003 CookieMonster::kMaxCookies
* 2,
2004 CookieMonster::kMaxCookies
+ CookieMonster::kPurgeCookies
+ 1,
2005 CookieMonster::kMaxCookies
* 2,
2006 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
},
2007 {// Old cookies enough to bring below our purge line (which we
2009 CookieMonster::kMaxCookies
* 2,
2010 CookieMonster::kMaxCookies
* 3 / 2,
2011 CookieMonster::kMaxCookies
* 2,
2012 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
}};
2014 for (int ci
= 0; ci
< static_cast<int>(arraysize(test_cases
)); ++ci
) {
2015 const TestCase
* test_case
= &test_cases
[ci
];
2016 scoped_refptr
<CookieMonster
> cm(CreateMonsterFromStoreForGC(
2017 test_case
->num_cookies
, test_case
->num_old_cookies
,
2018 CookieMonster::kSafeFromGlobalPurgeDays
* 2));
2019 EXPECT_EQ(test_case
->expected_initial_cookies
,
2020 GetAllCookies(cm
.get()).size())
2021 << "For test case " << ci
;
2023 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
2024 EXPECT_EQ(test_case
->expected_cookies_after_set
,
2025 GetAllCookies(cm
.get()).size())
2026 << "For test case " << ci
;
2030 // This test checks that keep expired cookies flag is working.
2031 TEST_F(CookieMonsterTest
, KeepExpiredCookies
) {
2032 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2033 cm
->SetKeepExpiredCookies();
2034 CookieOptions options
;
2036 // Set a persistent cookie.
2037 ASSERT_TRUE(SetCookieWithOptions(
2038 cm
.get(), url_google_
,
2039 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2042 // Get the canonical cookie.
2043 CookieList cookie_list
= GetAllCookies(cm
.get());
2044 ASSERT_EQ(1U, cookie_list
.size());
2046 // Use a past expiry date to delete the cookie.
2047 ASSERT_TRUE(SetCookieWithOptions(
2048 cm
.get(), url_google_
,
2049 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2052 // Check that the cookie with the past expiry date is still there.
2053 // GetAllCookies() also triggers garbage collection.
2054 cookie_list
= GetAllCookies(cm
.get());
2055 ASSERT_EQ(1U, cookie_list
.size());
2056 ASSERT_TRUE(cookie_list
[0].IsExpired(Time::Now()));
2061 // Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2062 class FlushablePersistentStore
: public CookieMonster::PersistentCookieStore
{
2064 FlushablePersistentStore() : flush_count_(0) {}
2066 void Load(const LoadedCallback
& loaded_callback
) override
{
2067 std::vector
<CanonicalCookie
*> out_cookies
;
2068 base::ThreadTaskRunnerHandle::Get()->PostTask(
2070 base::Bind(&LoadedCallbackTask::Run
,
2071 new LoadedCallbackTask(loaded_callback
, out_cookies
)));
2074 void LoadCookiesForKey(const std::string
& key
,
2075 const LoadedCallback
& loaded_callback
) override
{
2076 Load(loaded_callback
);
2079 void AddCookie(const CanonicalCookie
&) override
{}
2080 void UpdateCookieAccessTime(const CanonicalCookie
&) override
{}
2081 void DeleteCookie(const CanonicalCookie
&) override
{}
2082 void SetForceKeepSessionState() override
{}
2084 void Flush(const base::Closure
& callback
) override
{
2086 if (!callback
.is_null())
2090 int flush_count() { return flush_count_
; }
2093 ~FlushablePersistentStore() override
{}
2095 volatile int flush_count_
;
2098 // Counts the number of times Callback() has been run.
2099 class CallbackCounter
: public base::RefCountedThreadSafe
<CallbackCounter
> {
2101 CallbackCounter() : callback_count_(0) {}
2103 void Callback() { ++callback_count_
; }
2105 int callback_count() { return callback_count_
; }
2108 friend class base::RefCountedThreadSafe
<CallbackCounter
>;
2109 ~CallbackCounter() {}
2111 volatile int callback_count_
;
2116 // Test that FlushStore() is forwarded to the store and callbacks are posted.
2117 TEST_F(CookieMonsterTest
, FlushStore
) {
2118 scoped_refptr
<CallbackCounter
> counter(new CallbackCounter());
2119 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2120 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2122 ASSERT_EQ(0, store
->flush_count());
2123 ASSERT_EQ(0, counter
->callback_count());
2125 // Before initialization, FlushStore() should just run the callback.
2126 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2127 base::MessageLoop::current()->RunUntilIdle();
2129 ASSERT_EQ(0, store
->flush_count());
2130 ASSERT_EQ(1, counter
->callback_count());
2132 // NULL callback is safe.
2133 cm
->FlushStore(base::Closure());
2134 base::MessageLoop::current()->RunUntilIdle();
2136 ASSERT_EQ(0, store
->flush_count());
2137 ASSERT_EQ(1, counter
->callback_count());
2139 // After initialization, FlushStore() should delegate to the store.
2140 GetAllCookies(cm
.get()); // Force init.
2141 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2142 base::MessageLoop::current()->RunUntilIdle();
2144 ASSERT_EQ(1, store
->flush_count());
2145 ASSERT_EQ(2, counter
->callback_count());
2147 // NULL callback is still safe.
2148 cm
->FlushStore(base::Closure());
2149 base::MessageLoop::current()->RunUntilIdle();
2151 ASSERT_EQ(2, store
->flush_count());
2152 ASSERT_EQ(2, counter
->callback_count());
2154 // If there's no backing store, FlushStore() is always a safe no-op.
2155 cm
= new CookieMonster(NULL
, NULL
);
2156 GetAllCookies(cm
.get()); // Force init.
2157 cm
->FlushStore(base::Closure());
2158 base::MessageLoop::current()->RunUntilIdle();
2160 ASSERT_EQ(2, counter
->callback_count());
2162 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2163 base::MessageLoop::current()->RunUntilIdle();
2165 ASSERT_EQ(3, counter
->callback_count());
2168 TEST_F(CookieMonsterTest
, SetAllCookies
) {
2169 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2170 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2171 cm
->SetPersistSessionCookies(true);
2173 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "U=V; path=/"));
2174 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "W=X; path=/foo"));
2175 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "Y=Z; path=/"));
2178 list
.push_back(CanonicalCookie(url_google_
, "A", "B", url_google_
.host(), "/",
2179 base::Time::Now(), base::Time(), base::Time(),
2180 false, false, false, COOKIE_PRIORITY_DEFAULT
));
2181 list
.push_back(CanonicalCookie(url_google_
, "W", "X", url_google_
.host(),
2182 "/bar", base::Time::Now(), base::Time(),
2183 base::Time(), false, false, false,
2184 COOKIE_PRIORITY_DEFAULT
));
2185 list
.push_back(CanonicalCookie(url_google_
, "Y", "Z", url_google_
.host(), "/",
2186 base::Time::Now(), base::Time(), base::Time(),
2187 false, false, false, COOKIE_PRIORITY_DEFAULT
));
2189 // SetAllCookies must not flush.
2190 ASSERT_EQ(0, store
->flush_count());
2191 EXPECT_TRUE(SetAllCookies(cm
.get(), list
));
2192 EXPECT_EQ(0, store
->flush_count());
2194 CookieList cookies
= GetAllCookies(cm
.get());
2195 size_t expected_size
= 3; // "A", "W" and "Y". "U" is gone.
2196 EXPECT_EQ(expected_size
, cookies
.size());
2197 CookieList::iterator it
= cookies
.begin();
2199 ASSERT_TRUE(it
!= cookies
.end());
2200 EXPECT_EQ("W", it
->Name());
2201 EXPECT_EQ("X", it
->Value());
2202 EXPECT_EQ("/bar", it
->Path()); // The path has been updated.
2204 ASSERT_TRUE(++it
!= cookies
.end());
2205 EXPECT_EQ("A", it
->Name());
2206 EXPECT_EQ("B", it
->Value());
2208 ASSERT_TRUE(++it
!= cookies
.end());
2209 EXPECT_EQ("Y", it
->Name());
2210 EXPECT_EQ("Z", it
->Value());
2213 TEST_F(CookieMonsterTest
, ComputeCookieDiff
) {
2214 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2216 base::Time now
= base::Time::Now();
2217 base::Time creation_time
= now
- base::TimeDelta::FromSeconds(1);
2219 CanonicalCookie
cookie1(url_google_
, "A", "B", url_google_
.host(), "/",
2220 creation_time
, base::Time(), base::Time(), false,
2221 false, false, COOKIE_PRIORITY_DEFAULT
);
2222 CanonicalCookie
cookie2(url_google_
, "C", "D", url_google_
.host(), "/",
2223 creation_time
, base::Time(), base::Time(), false,
2224 false, false, COOKIE_PRIORITY_DEFAULT
);
2225 CanonicalCookie
cookie3(url_google_
, "E", "F", url_google_
.host(), "/",
2226 creation_time
, base::Time(), base::Time(), false,
2227 false, false, COOKIE_PRIORITY_DEFAULT
);
2228 CanonicalCookie
cookie4(url_google_
, "G", "H", url_google_
.host(), "/",
2229 creation_time
, base::Time(), base::Time(), false,
2230 false, false, COOKIE_PRIORITY_DEFAULT
);
2231 CanonicalCookie
cookie4_with_new_value(
2232 url_google_
, "G", "iamnew", url_google_
.host(), "/", creation_time
,
2233 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2234 CanonicalCookie
cookie5(url_google_
, "I", "J", url_google_
.host(), "/",
2235 creation_time
, base::Time(), base::Time(), false,
2236 false, false, COOKIE_PRIORITY_DEFAULT
);
2237 CanonicalCookie
cookie5_with_new_creation_time(
2238 url_google_
, "I", "J", url_google_
.host(), "/", now
, base::Time(),
2239 base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2240 CanonicalCookie
cookie6(url_google_
, "K", "L", url_google_
.host(), "/foo",
2241 creation_time
, base::Time(), base::Time(), false,
2242 false, false, COOKIE_PRIORITY_DEFAULT
);
2243 CanonicalCookie
cookie6_with_new_path(
2244 url_google_
, "K", "L", url_google_
.host(), "/bar", creation_time
,
2245 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2246 CanonicalCookie
cookie7(url_google_
, "M", "N", url_google_
.host(), "/foo",
2247 creation_time
, base::Time(), base::Time(), false,
2248 false, false, COOKIE_PRIORITY_DEFAULT
);
2249 CanonicalCookie
cookie7_with_new_path(
2250 url_google_
, "M", "N", url_google_
.host(), "/bar", creation_time
,
2251 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
);
2253 CookieList old_cookies
;
2254 old_cookies
.push_back(cookie1
);
2255 old_cookies
.push_back(cookie2
);
2256 old_cookies
.push_back(cookie4
);
2257 old_cookies
.push_back(cookie5
);
2258 old_cookies
.push_back(cookie6
);
2259 old_cookies
.push_back(cookie7
);
2261 CookieList new_cookies
;
2262 new_cookies
.push_back(cookie1
);
2263 new_cookies
.push_back(cookie3
);
2264 new_cookies
.push_back(cookie4_with_new_value
);
2265 new_cookies
.push_back(cookie5_with_new_creation_time
);
2266 new_cookies
.push_back(cookie6_with_new_path
);
2267 new_cookies
.push_back(cookie7
);
2268 new_cookies
.push_back(cookie7_with_new_path
);
2270 CookieList cookies_to_add
;
2271 CookieList cookies_to_delete
;
2273 cm
->ComputeCookieDiff(&old_cookies
, &new_cookies
, &cookies_to_add
,
2274 &cookies_to_delete
);
2276 // |cookie1| has not changed.
2277 EXPECT_FALSE(IsCookieInList(cookie1
, cookies_to_add
));
2278 EXPECT_FALSE(IsCookieInList(cookie1
, cookies_to_delete
));
2280 // |cookie2| has been deleted.
2281 EXPECT_FALSE(IsCookieInList(cookie2
, cookies_to_add
));
2282 EXPECT_TRUE(IsCookieInList(cookie2
, cookies_to_delete
));
2284 // |cookie3| has been added.
2285 EXPECT_TRUE(IsCookieInList(cookie3
, cookies_to_add
));
2286 EXPECT_FALSE(IsCookieInList(cookie3
, cookies_to_delete
));
2288 // |cookie4| has a new value: new cookie overrides the old one (which does not
2289 // need to be explicitly removed).
2290 EXPECT_FALSE(IsCookieInList(cookie4
, cookies_to_add
));
2291 EXPECT_FALSE(IsCookieInList(cookie4
, cookies_to_delete
));
2292 EXPECT_TRUE(IsCookieInList(cookie4_with_new_value
, cookies_to_add
));
2293 EXPECT_FALSE(IsCookieInList(cookie4_with_new_value
, cookies_to_delete
));
2295 // |cookie5| has a new creation time: new cookie overrides the old one (which
2296 // does not need to be explicitly removed).
2297 EXPECT_FALSE(IsCookieInList(cookie5
, cookies_to_add
));
2298 EXPECT_FALSE(IsCookieInList(cookie5
, cookies_to_delete
));
2299 EXPECT_TRUE(IsCookieInList(cookie5_with_new_creation_time
, cookies_to_add
));
2301 IsCookieInList(cookie5_with_new_creation_time
, cookies_to_delete
));
2303 // |cookie6| has a new path: the new cookie does not overrides the old one,
2304 // which needs to be explicitly removed.
2305 EXPECT_FALSE(IsCookieInList(cookie6
, cookies_to_add
));
2306 EXPECT_TRUE(IsCookieInList(cookie6
, cookies_to_delete
));
2307 EXPECT_TRUE(IsCookieInList(cookie6_with_new_path
, cookies_to_add
));
2308 EXPECT_FALSE(IsCookieInList(cookie6_with_new_path
, cookies_to_delete
));
2310 // |cookie7| is kept and |cookie7_with_new_path| is added as a new cookie.
2311 EXPECT_FALSE(IsCookieInList(cookie7
, cookies_to_add
));
2312 EXPECT_FALSE(IsCookieInList(cookie7
, cookies_to_delete
));
2313 EXPECT_TRUE(IsCookieInList(cookie7_with_new_path
, cookies_to_add
));
2314 EXPECT_FALSE(IsCookieInList(cookie7_with_new_path
, cookies_to_delete
));
2317 // Check that DeleteAll does flush (as a sanity check that flush_count()
2319 TEST_F(CookieMonsterTest
, DeleteAll
) {
2320 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2321 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2322 cm
->SetPersistSessionCookies(true);
2324 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "X=Y; path=/"));
2326 ASSERT_EQ(0, store
->flush_count());
2327 EXPECT_EQ(1, DeleteAll(cm
.get()));
2328 EXPECT_EQ(1, store
->flush_count());
2331 TEST_F(CookieMonsterTest
, HistogramCheck
) {
2332 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2333 // Should match call in InitializeHistograms, but doesn't really matter
2334 // since the histogram should have been initialized by the CM construction
2336 base::HistogramBase
* expired_histogram
= base::Histogram::FactoryGet(
2337 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2338 base::Histogram::kUmaTargetedHistogramFlag
);
2340 scoped_ptr
<base::HistogramSamples
> samples1(
2341 expired_histogram
->SnapshotSamples());
2342 ASSERT_TRUE(SetCookieWithDetails(
2343 cm
.get(), GURL("http://fake.a.url"), "a", "b", "a.url", "/",
2344 base::Time::Now() + base::TimeDelta::FromMinutes(59), false, false, false,
2345 COOKIE_PRIORITY_DEFAULT
));
2347 scoped_ptr
<base::HistogramSamples
> samples2(
2348 expired_histogram
->SnapshotSamples());
2349 EXPECT_EQ(samples1
->TotalCount() + 1, samples2
->TotalCount());
2351 // kValidCookieLine creates a session cookie.
2352 ASSERT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
2354 scoped_ptr
<base::HistogramSamples
> samples3(
2355 expired_histogram
->SnapshotSamples());
2356 EXPECT_EQ(samples2
->TotalCount(), samples3
->TotalCount());
2361 class MultiThreadedCookieMonsterTest
: public CookieMonsterTest
{
2363 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {}
2365 // Helper methods for calling the asynchronous CookieMonster methods
2366 // from a different thread.
2368 void GetAllCookiesTask(CookieMonster
* cm
, GetCookieListCallback
* callback
) {
2369 cm
->GetAllCookiesAsync(
2370 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2373 void GetAllCookiesForURLTask(CookieMonster
* cm
,
2375 GetCookieListCallback
* callback
) {
2376 cm
->GetAllCookiesForURLAsync(url
, base::Bind(&GetCookieListCallback::Run
,
2377 base::Unretained(callback
)));
2380 void GetAllCookiesForURLWithOptionsTask(CookieMonster
* cm
,
2382 const CookieOptions
& options
,
2383 GetCookieListCallback
* callback
) {
2384 cm
->GetAllCookiesForURLWithOptionsAsync(
2386 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2389 void SetCookieWithDetailsTask(CookieMonster
* cm
,
2391 ResultSavingCookieCallback
<bool>* callback
) {
2392 // Define the parameters here instead of in the calling fucntion.
2393 // The maximum number of parameters for Bind function is 6.
2394 std::string name
= "A";
2395 std::string value
= "B";
2396 std::string domain
= std::string();
2397 std::string path
= "/foo";
2398 base::Time expiration_time
= base::Time();
2399 bool secure
= false;
2400 bool http_only
= false;
2401 bool first_party_only
= false;
2402 CookiePriority priority
= COOKIE_PRIORITY_DEFAULT
;
2403 cm
->SetCookieWithDetailsAsync(
2404 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
2405 first_party_only
, priority
,
2406 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
2407 base::Unretained(callback
)));
2410 void DeleteAllCreatedBetweenTask(CookieMonster
* cm
,
2411 const base::Time
& delete_begin
,
2412 const base::Time
& delete_end
,
2413 ResultSavingCookieCallback
<int>* callback
) {
2414 cm
->DeleteAllCreatedBetweenAsync(
2415 delete_begin
, delete_end
,
2416 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2417 base::Unretained(callback
)));
2420 void DeleteAllForHostTask(CookieMonster
* cm
,
2422 ResultSavingCookieCallback
<int>* callback
) {
2423 cm
->DeleteAllForHostAsync(url
,
2424 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2425 base::Unretained(callback
)));
2428 void DeleteAllCreatedBetweenForHostTask(
2430 const base::Time delete_begin
,
2431 const base::Time delete_end
,
2433 ResultSavingCookieCallback
<int>* callback
) {
2434 cm
->DeleteAllCreatedBetweenForHostAsync(
2435 delete_begin
, delete_end
, url
,
2436 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2437 base::Unretained(callback
)));
2440 void DeleteCanonicalCookieTask(CookieMonster
* cm
,
2441 const CanonicalCookie
& cookie
,
2442 ResultSavingCookieCallback
<bool>* callback
) {
2443 cm
->DeleteCanonicalCookieAsync(
2444 cookie
, base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
2445 base::Unretained(callback
)));
2449 void RunOnOtherThread(const base::Closure
& task
) {
2450 other_thread_
.Start();
2451 other_thread_
.task_runner()->PostTask(FROM_HERE
, task
);
2453 other_thread_
.Stop();
2456 Thread other_thread_
;
2461 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookies
) {
2462 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2463 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2464 CookieList cookies
= GetAllCookies(cm
.get());
2465 CookieList::const_iterator it
= cookies
.begin();
2466 ASSERT_TRUE(it
!= cookies
.end());
2467 EXPECT_EQ("www.google.izzle", it
->Domain());
2468 EXPECT_EQ("A", it
->Name());
2469 ASSERT_TRUE(++it
== cookies
.end());
2470 GetCookieListCallback
callback(&other_thread_
);
2471 base::Closure task
=
2472 base::Bind(&MultiThreadedCookieMonsterTest::GetAllCookiesTask
,
2473 base::Unretained(this), cm
, &callback
);
2474 RunOnOtherThread(task
);
2475 EXPECT_TRUE(callback
.did_run());
2476 it
= callback
.cookies().begin();
2477 ASSERT_TRUE(it
!= callback
.cookies().end());
2478 EXPECT_EQ("www.google.izzle", it
->Domain());
2479 EXPECT_EQ("A", it
->Name());
2480 ASSERT_TRUE(++it
== callback
.cookies().end());
2483 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURL
) {
2484 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2485 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2486 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
2487 CookieList::const_iterator it
= cookies
.begin();
2488 ASSERT_TRUE(it
!= cookies
.end());
2489 EXPECT_EQ("www.google.izzle", it
->Domain());
2490 EXPECT_EQ("A", it
->Name());
2491 ASSERT_TRUE(++it
== cookies
.end());
2492 GetCookieListCallback
callback(&other_thread_
);
2493 base::Closure task
=
2494 base::Bind(&MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask
,
2495 base::Unretained(this), cm
, url_google_
, &callback
);
2496 RunOnOtherThread(task
);
2497 EXPECT_TRUE(callback
.did_run());
2498 it
= callback
.cookies().begin();
2499 ASSERT_TRUE(it
!= callback
.cookies().end());
2500 EXPECT_EQ("www.google.izzle", it
->Domain());
2501 EXPECT_EQ("A", it
->Name());
2502 ASSERT_TRUE(++it
== callback
.cookies().end());
2505 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURLWithOpt
) {
2506 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2507 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2508 CookieOptions options
;
2509 CookieList cookies
=
2510 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, options
);
2511 CookieList::const_iterator it
= cookies
.begin();
2512 ASSERT_TRUE(it
!= cookies
.end());
2513 EXPECT_EQ("www.google.izzle", it
->Domain());
2514 EXPECT_EQ("A", it
->Name());
2515 ASSERT_TRUE(++it
== cookies
.end());
2516 GetCookieListCallback
callback(&other_thread_
);
2517 base::Closure task
= base::Bind(
2518 &MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask
,
2519 base::Unretained(this), cm
, url_google_
, options
, &callback
);
2520 RunOnOtherThread(task
);
2521 EXPECT_TRUE(callback
.did_run());
2522 it
= callback
.cookies().begin();
2523 ASSERT_TRUE(it
!= callback
.cookies().end());
2524 EXPECT_EQ("www.google.izzle", it
->Domain());
2525 EXPECT_EQ("A", it
->Name());
2526 ASSERT_TRUE(++it
== callback
.cookies().end());
2529 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckSetCookieWithDetails
) {
2530 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2531 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A", "B",
2532 std::string(), "/foo", base::Time(), false,
2533 false, false, COOKIE_PRIORITY_DEFAULT
));
2534 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2535 base::Closure task
=
2536 base::Bind(&MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask
,
2537 base::Unretained(this), cm
, url_google_foo_
, &callback
);
2538 RunOnOtherThread(task
);
2539 EXPECT_TRUE(callback
.did_run());
2540 EXPECT_TRUE(callback
.result());
2543 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllCreatedBetween
) {
2544 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2545 CookieOptions options
;
2546 Time now
= Time::Now();
2547 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2548 EXPECT_EQ(1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99),
2550 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2551 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2552 base::Closure task
=
2553 base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask
,
2554 base::Unretained(this), cm
, now
- TimeDelta::FromDays(99),
2556 RunOnOtherThread(task
);
2557 EXPECT_TRUE(callback
.did_run());
2558 EXPECT_EQ(1, callback
.result());
2561 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllForHost
) {
2562 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2563 CookieOptions options
;
2564 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2565 EXPECT_EQ(1, DeleteAllForHost(cm
.get(), url_google_
));
2566 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2567 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2568 base::Closure task
=
2569 base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllForHostTask
,
2570 base::Unretained(this), cm
, url_google_
, &callback
);
2571 RunOnOtherThread(task
);
2572 EXPECT_TRUE(callback
.did_run());
2573 EXPECT_EQ(1, callback
.result());
2576 TEST_F(MultiThreadedCookieMonsterTest
,
2577 ThreadCheckDeleteAllCreatedBetweenForHost
) {
2578 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2579 GURL
url_not_google("http://www.notgoogle.com");
2581 CookieOptions options
;
2582 Time now
= Time::Now();
2583 // ago1 < ago2 < ago3 < now.
2584 Time ago1
= now
- TimeDelta::FromDays(101);
2585 Time ago2
= now
- TimeDelta::FromDays(100);
2586 Time ago3
= now
- TimeDelta::FromDays(99);
2588 // These 3 cookies match the first deletion.
2589 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2590 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "C=D", options
));
2591 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "Y=Z", options
));
2593 // This cookie does not match host.
2594 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_not_google
, "E=F", options
));
2596 // This cookie does not match time range: [ago3, inf], for first deletion, but
2597 // matches for the second deletion.
2598 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "G=H", ago2
));
2600 // 1. First set of deletions.
2602 3, // Deletes A=B, C=D, Y=Z
2603 DeleteAllCreatedBetweenForHost(cm
.get(), ago3
, Time::Max(), url_google_
));
2605 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2606 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2608 // 2. Second set of deletions.
2609 base::Closure task
= base::Bind(
2610 &MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask
,
2611 base::Unretained(this), cm
, ago1
, Time(), url_google_
, &callback
);
2612 RunOnOtherThread(task
);
2613 EXPECT_TRUE(callback
.did_run());
2614 EXPECT_EQ(2, callback
.result()); // Deletes A=B, G=H.
2617 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteCanonicalCookie
) {
2618 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2619 CookieOptions options
;
2620 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2621 CookieList cookies
= GetAllCookies(cm
.get());
2622 CookieList::iterator it
= cookies
.begin();
2623 EXPECT_TRUE(DeleteCanonicalCookie(cm
.get(), *it
));
2625 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2626 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2627 cookies
= GetAllCookies(cm
.get());
2628 it
= cookies
.begin();
2629 base::Closure task
=
2630 base::Bind(&MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask
,
2631 base::Unretained(this), cm
, *it
, &callback
);
2632 RunOnOtherThread(task
);
2633 EXPECT_TRUE(callback
.did_run());
2634 EXPECT_TRUE(callback
.result());
2637 // Ensure that cookies for http, https, ws, and wss all share the same storage
2638 // and policies when GetAllCookiesForURLAsync is used. This test is part of
2639 // MultiThreadedCookieMonsterTest in order to test and use
2640 // GetAllCookiesForURLAsync, but it does not use any additional threads.
2641 TEST_F(MultiThreadedCookieMonsterTest
, GetAllCookiesForURLEffectiveDomain
) {
2642 std::vector
<CanonicalCookie
*> cookies
;
2643 // This cookie will be freed by the CookieMonster.
2644 cookies
.push_back(CanonicalCookie::Create(url_google_
, kValidCookieLine
,
2645 Time::Now(), CookieOptions()));
2646 CanonicalCookie cookie
= *cookies
[0];
2647 scoped_refptr
<NewMockPersistentCookieStore
> store(
2648 new NewMockPersistentCookieStore
);
2649 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2651 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback
;
2652 ::testing::StrictMock
<::testing::MockFunction
<void(int)>> checkpoint
;
2653 const std::string key
=
2654 cookie_util::GetEffectiveDomain(url_google_
.scheme(), url_google_
.host());
2656 ::testing::InSequence s
;
2657 EXPECT_CALL(checkpoint
, Call(0));
2658 EXPECT_CALL(*store
, Load(::testing::_
));
2659 EXPECT_CALL(*store
, LoadCookiesForKey(key
, ::testing::_
))
2660 .WillOnce(::testing::SaveArg
<1>(&loaded_callback
));
2661 EXPECT_CALL(checkpoint
, Call(1));
2662 // LoadCookiesForKey will never be called after checkpoint.Call(1) although
2663 // we will call GetAllCookiesForURLAsync again, because all URLs below share
2665 EXPECT_CALL(*store
, LoadCookiesForKey(::testing::_
, ::testing::_
)).Times(0);
2667 GetCookieListCallback callback
;
2669 GetAllCookiesForURLTask(cm
.get(), url_google_
, &callback
);
2671 ASSERT_FALSE(callback
.did_run());
2672 // Pass the cookies to the CookieMonster.
2673 loaded_callback
.Run(cookies
);
2674 // Now GetAllCookiesForURLTask is done.
2675 ASSERT_TRUE(callback
.did_run());
2676 // See that the callback was called with the cookies.
2677 ASSERT_EQ(1u, callback
.cookies().size());
2678 EXPECT_TRUE(cookie
.IsEquivalent(callback
.cookies()[0]));
2680 // All urls in |urls| should share the same cookie domain.
2681 const GURL kUrls
[] = {
2684 GURL(kUrlGoogleWebSocket
),
2685 GURL(kUrlGoogleWebSocketSecure
),
2687 for (const GURL
& url
: kUrls
) {
2688 // Call the function with |url| and verify it is done synchronously without
2689 // calling LoadCookiesForKey.
2690 GetCookieListCallback callback
;
2691 GetAllCookiesForURLTask(cm
.get(), url
, &callback
);
2692 ASSERT_TRUE(callback
.did_run());
2693 ASSERT_EQ(1u, callback
.cookies().size());
2694 EXPECT_TRUE(cookie
.IsEquivalent(callback
.cookies()[0]));
2698 TEST_F(CookieMonsterTest
, InvalidExpiryTime
) {
2699 std::string cookie_line
=
2700 std::string(kValidCookieLine
) + "; expires=Blarg arg arg";
2701 scoped_ptr
<CanonicalCookie
> cookie(CanonicalCookie::Create(
2702 url_google_
, cookie_line
, Time::Now(), CookieOptions()));
2703 ASSERT_FALSE(cookie
->IsPersistent());
2706 // Test that CookieMonster writes session cookies into the underlying
2707 // CookieStore if the "persist session cookies" option is on.
2708 TEST_F(CookieMonsterTest
, PersistSessionCookies
) {
2709 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2710 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2711 cm
->SetPersistSessionCookies(true);
2713 // All cookies set with SetCookie are session cookies.
2714 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2715 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
2717 // The cookie was written to the backing store.
2718 EXPECT_EQ(1u, store
->commands().size());
2719 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2720 EXPECT_EQ("A", store
->commands()[0].cookie
.Name());
2721 EXPECT_EQ("B", store
->commands()[0].cookie
.Value());
2723 // Modify the cookie.
2724 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=C"));
2725 EXPECT_EQ("A=C", GetCookies(cm
.get(), url_google_
));
2726 EXPECT_EQ(3u, store
->commands().size());
2727 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2728 EXPECT_EQ("A", store
->commands()[1].cookie
.Name());
2729 EXPECT_EQ("B", store
->commands()[1].cookie
.Value());
2730 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2731 EXPECT_EQ("A", store
->commands()[2].cookie
.Name());
2732 EXPECT_EQ("C", store
->commands()[2].cookie
.Value());
2734 // Delete the cookie.
2735 DeleteCookie(cm
.get(), url_google_
, "A");
2736 EXPECT_EQ("", GetCookies(cm
.get(), url_google_
));
2737 EXPECT_EQ(4u, store
->commands().size());
2738 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2739 EXPECT_EQ("A", store
->commands()[3].cookie
.Name());
2740 EXPECT_EQ("C", store
->commands()[3].cookie
.Value());
2743 // Test the commands sent to the persistent cookie store.
2744 TEST_F(CookieMonsterTest
, PersisentCookieStorageTest
) {
2745 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2746 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2749 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2750 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2751 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2752 ASSERT_EQ(1u, store
->commands().size());
2753 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2755 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B; max-age=0"));
2756 this->MatchCookieLines(std::string(), GetCookies(cm
.get(), url_google_
));
2757 ASSERT_EQ(2u, store
->commands().size());
2758 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2761 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2762 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2763 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2764 ASSERT_EQ(3u, store
->commands().size());
2765 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2767 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2768 "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
2769 this->MatchCookieLines("A=Foo", GetCookies(cm
.get(), url_google_
));
2770 ASSERT_EQ(5u, store
->commands().size());
2771 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2772 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[4].type
);
2774 // Create some non-persistent cookies and check that they don't go to the
2775 // persistent storage.
2776 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=Bar"));
2777 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm
.get(), url_google_
));
2778 EXPECT_EQ(5u, store
->commands().size());
2781 // Test to assure that cookies with control characters are purged appropriately.
2782 // See http://crbug.com/238041 for background.
2783 TEST_F(CookieMonsterTest
, ControlCharacterPurge
) {
2784 const Time
now1(Time::Now());
2785 const Time
now2(Time::Now() + TimeDelta::FromSeconds(1));
2786 const Time
now3(Time::Now() + TimeDelta::FromSeconds(2));
2787 const Time
later(now1
+ TimeDelta::FromDays(1));
2788 const GURL
url("http://host/path");
2789 const std::string
domain("host");
2790 const std::string
path("/path");
2792 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2794 std::vector
<CanonicalCookie
*> initial_cookies
;
2796 AddCookieToList(domain
, "foo=bar; path=" + path
, now1
, &initial_cookies
);
2798 // We have to manually build this cookie because it contains a control
2799 // character, and our cookie line parser rejects control characters.
2800 CanonicalCookie
* cc
=
2801 new CanonicalCookie(url
, "baz",
2804 domain
, path
, now2
, later
, now2
, false, false, false,
2805 COOKIE_PRIORITY_DEFAULT
);
2806 initial_cookies
.push_back(cc
);
2808 AddCookieToList(domain
, "hello=world; path=" + path
, now3
, &initial_cookies
);
2810 // Inject our initial cookies into the mock PersistentCookieStore.
2811 store
->SetLoadExpectation(true, initial_cookies
);
2813 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2815 EXPECT_EQ("foo=bar; hello=world", GetCookies(cm
.get(), url
));
2818 class CookieMonsterNotificationTest
: public CookieMonsterTest
{
2820 CookieMonsterNotificationTest()
2821 : test_url_("http://www.google.com/foo"),
2822 store_(new MockPersistentCookieStore
),
2823 monster_(new CookieMonster(store_
.get(), NULL
)) {}
2825 ~CookieMonsterNotificationTest() override
{}
2827 CookieMonster
* monster() { return monster_
.get(); }
2830 const GURL test_url_
;
2833 scoped_refptr
<MockPersistentCookieStore
> store_
;
2834 scoped_refptr
<CookieMonster
> monster_
;
2837 void RecordCookieChanges(std::vector
<CanonicalCookie
>* out_cookies
,
2838 std::vector
<bool>* out_removes
,
2839 const CanonicalCookie
& cookie
,
2841 DCHECK(out_cookies
);
2842 out_cookies
->push_back(cookie
);
2844 out_removes
->push_back(removed
);
2847 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithNoCookie
) {
2848 std::vector
<CanonicalCookie
> cookies
;
2849 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2850 monster()->AddCallbackForCookie(
2852 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2853 base::MessageLoop::current()->RunUntilIdle();
2854 EXPECT_EQ(0U, cookies
.size());
2857 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithInitialCookie
) {
2858 std::vector
<CanonicalCookie
> cookies
;
2859 SetCookie(monster(), test_url_
, "abc=def");
2860 base::MessageLoop::current()->RunUntilIdle();
2861 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2862 monster()->AddCallbackForCookie(
2864 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2865 base::MessageLoop::current()->RunUntilIdle();
2866 EXPECT_EQ(0U, cookies
.size());
2869 TEST_F(CookieMonsterNotificationTest
, NotifyOnSet
) {
2870 std::vector
<CanonicalCookie
> cookies
;
2871 std::vector
<bool> removes
;
2872 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2873 monster()->AddCallbackForCookie(
2875 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2876 SetCookie(monster(), test_url_
, "abc=def");
2877 base::MessageLoop::current()->RunUntilIdle();
2878 EXPECT_EQ(1U, cookies
.size());
2879 EXPECT_EQ(1U, removes
.size());
2881 EXPECT_EQ("abc", cookies
[0].Name());
2882 EXPECT_EQ("def", cookies
[0].Value());
2883 EXPECT_FALSE(removes
[0]);
2886 TEST_F(CookieMonsterNotificationTest
, NotifyOnDelete
) {
2887 std::vector
<CanonicalCookie
> cookies
;
2888 std::vector
<bool> removes
;
2889 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2890 monster()->AddCallbackForCookie(
2892 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2893 SetCookie(monster(), test_url_
, "abc=def");
2894 base::MessageLoop::current()->RunUntilIdle();
2895 EXPECT_EQ(1U, cookies
.size());
2896 EXPECT_EQ(1U, removes
.size());
2898 DeleteCookie(monster(), test_url_
, "abc");
2899 base::MessageLoop::current()->RunUntilIdle();
2900 EXPECT_EQ(2U, cookies
.size());
2901 EXPECT_EQ(2U, removes
.size());
2903 EXPECT_EQ("abc", cookies
[1].Name());
2904 EXPECT_EQ("def", cookies
[1].Value());
2905 EXPECT_TRUE(removes
[1]);
2908 TEST_F(CookieMonsterNotificationTest
, NotifyOnUpdate
) {
2909 std::vector
<CanonicalCookie
> cookies
;
2910 std::vector
<bool> removes
;
2911 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2912 monster()->AddCallbackForCookie(
2914 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2915 SetCookie(monster(), test_url_
, "abc=def");
2916 base::MessageLoop::current()->RunUntilIdle();
2917 EXPECT_EQ(1U, cookies
.size());
2919 // Replacing an existing cookie is actually a two-phase delete + set
2920 // operation, so we get an extra notification.
2921 SetCookie(monster(), test_url_
, "abc=ghi");
2922 base::MessageLoop::current()->RunUntilIdle();
2924 EXPECT_EQ(3U, cookies
.size());
2925 EXPECT_EQ(3U, removes
.size());
2927 EXPECT_EQ("abc", cookies
[1].Name());
2928 EXPECT_EQ("def", cookies
[1].Value());
2929 EXPECT_TRUE(removes
[1]);
2931 EXPECT_EQ("abc", cookies
[2].Name());
2932 EXPECT_EQ("ghi", cookies
[2].Value());
2933 EXPECT_FALSE(removes
[2]);
2936 TEST_F(CookieMonsterNotificationTest
, MultipleNotifies
) {
2937 std::vector
<CanonicalCookie
> cookies0
;
2938 std::vector
<CanonicalCookie
> cookies1
;
2939 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
2940 monster()->AddCallbackForCookie(
2942 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
2943 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
2944 monster()->AddCallbackForCookie(
2946 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
2947 SetCookie(monster(), test_url_
, "abc=def");
2948 base::MessageLoop::current()->RunUntilIdle();
2949 EXPECT_EQ(1U, cookies0
.size());
2950 EXPECT_EQ(0U, cookies1
.size());
2951 SetCookie(monster(), test_url_
, "def=abc");
2952 base::MessageLoop::current()->RunUntilIdle();
2953 EXPECT_EQ(1U, cookies0
.size());
2954 EXPECT_EQ(1U, cookies1
.size());
2957 TEST_F(CookieMonsterNotificationTest
, MultipleSameNotifies
) {
2958 std::vector
<CanonicalCookie
> cookies0
;
2959 std::vector
<CanonicalCookie
> cookies1
;
2960 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
2961 monster()->AddCallbackForCookie(
2963 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
2964 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
2965 monster()->AddCallbackForCookie(
2967 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
2968 SetCookie(monster(), test_url_
, "abc=def");
2969 base::MessageLoop::current()->RunUntilIdle();
2970 EXPECT_EQ(1U, cookies0
.size());
2971 EXPECT_EQ(1U, cookies0
.size());