1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/cookies/cookie_store_unittest.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/scoped_vector.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/histogram.h"
18 #include "base/metrics/histogram_samples.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_piece.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_tokenizer.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/threading/thread.h"
25 #include "base/time/time.h"
26 #include "net/cookies/canonical_cookie.h"
27 #include "net/cookies/cookie_constants.h"
28 #include "net/cookies/cookie_monster.h"
29 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
30 #include "net/cookies/cookie_util.h"
31 #include "net/cookies/parsed_cookie.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
39 using base::TimeDelta
;
43 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and
44 // brethren) with this one, and remove the 'New' prefix.
45 class NewMockPersistentCookieStore
46 : public CookieMonster::PersistentCookieStore
{
48 MOCK_METHOD1(Load
, void(const LoadedCallback
& loaded_callback
));
49 MOCK_METHOD2(LoadCookiesForKey
,
50 void(const std::string
& key
,
51 const LoadedCallback
& loaded_callback
));
52 MOCK_METHOD1(AddCookie
, void(const CanonicalCookie
& cc
));
53 MOCK_METHOD1(UpdateCookieAccessTime
, void(const CanonicalCookie
& cc
));
54 MOCK_METHOD1(DeleteCookie
, void(const CanonicalCookie
& cc
));
55 virtual void Flush(const base::Closure
& callback
) {
56 if (!callback
.is_null())
57 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
59 MOCK_METHOD0(SetForceKeepSessionState
, void());
62 virtual ~NewMockPersistentCookieStore() {}
65 const char kTopLevelDomainPlus1
[] = "http://www.harvard.edu";
66 const char kTopLevelDomainPlus2
[] = "http://www.math.harvard.edu";
67 const char kTopLevelDomainPlus2Secure
[] = "https://www.math.harvard.edu";
68 const char kTopLevelDomainPlus3
[] = "http://www.bourbaki.math.harvard.edu";
69 const char kOtherDomain
[] = "http://www.mit.edu";
70 const char kUrlGoogleSpecific
[] = "http://www.gmail.google.izzle";
72 class GetCookieListCallback
: public CookieCallback
{
74 GetCookieListCallback() {}
75 explicit GetCookieListCallback(Thread
* run_in_thread
)
76 : CookieCallback(run_in_thread
) {}
78 void Run(const CookieList
& cookies
) {
83 const CookieList
& cookies() { return cookies_
; }
89 struct CookieMonsterTestTraits
{
90 static scoped_refptr
<CookieStore
> Create() {
91 return new CookieMonster(NULL
, NULL
);
94 static const bool is_cookie_monster
= true;
95 static const bool supports_http_only
= true;
96 static const bool supports_non_dotted_domains
= true;
97 static const bool supports_trailing_dots
= true;
98 static const bool filters_schemes
= true;
99 static const bool has_path_prefix_bug
= false;
100 static const int creation_time_granularity_in_ms
= 0;
103 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
105 CookieMonsterTestTraits
);
107 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster
,
108 MultiThreadedCookieStoreTest
,
109 CookieMonsterTestTraits
);
111 class CookieMonsterTest
: public CookieStoreTest
<CookieMonsterTestTraits
> {
113 CookieList
GetAllCookies(CookieMonster
* cm
) {
115 GetCookieListCallback callback
;
116 cm
->GetAllCookiesAsync(
117 base::Bind(&GetCookieListCallback::Run
, base::Unretained(&callback
)));
119 EXPECT_TRUE(callback
.did_run());
120 return callback
.cookies();
123 CookieList
GetAllCookiesForURL(CookieMonster
* cm
, const GURL
& url
) {
125 GetCookieListCallback callback
;
126 cm
->GetAllCookiesForURLAsync(url
, base::Bind(&GetCookieListCallback::Run
,
127 base::Unretained(&callback
)));
129 EXPECT_TRUE(callback
.did_run());
130 return callback
.cookies();
133 CookieList
GetAllCookiesForURLWithOptions(CookieMonster
* cm
,
135 const CookieOptions
& options
) {
137 GetCookieListCallback callback
;
138 cm
->GetAllCookiesForURLWithOptionsAsync(
140 base::Bind(&GetCookieListCallback::Run
, base::Unretained(&callback
)));
142 EXPECT_TRUE(callback
.did_run());
143 return callback
.cookies();
146 bool SetCookieWithDetails(CookieMonster
* cm
,
148 const std::string
& name
,
149 const std::string
& value
,
150 const std::string
& domain
,
151 const std::string
& path
,
152 const base::Time
& expiration_time
,
155 bool first_party_only
,
156 CookiePriority priority
) {
158 ResultSavingCookieCallback
<bool> callback
;
159 cm
->SetCookieWithDetailsAsync(
160 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
161 first_party_only
, priority
,
162 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
163 base::Unretained(&callback
)));
165 EXPECT_TRUE(callback
.did_run());
166 return callback
.result();
169 int DeleteAll(CookieMonster
* cm
) {
171 ResultSavingCookieCallback
<int> callback
;
172 cm
->DeleteAllAsync(base::Bind(&ResultSavingCookieCallback
<int>::Run
,
173 base::Unretained(&callback
)));
175 EXPECT_TRUE(callback
.did_run());
176 return callback
.result();
179 int DeleteAllCreatedBetween(CookieMonster
* cm
,
180 const base::Time
& delete_begin
,
181 const base::Time
& delete_end
) {
183 ResultSavingCookieCallback
<int> callback
;
184 cm
->DeleteAllCreatedBetweenAsync(
185 delete_begin
, delete_end
,
186 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
187 base::Unretained(&callback
)));
189 EXPECT_TRUE(callback
.did_run());
190 return callback
.result();
193 int DeleteAllCreatedBetweenForHost(CookieMonster
* cm
,
194 const base::Time delete_begin
,
195 const base::Time delete_end
,
198 ResultSavingCookieCallback
<int> callback
;
199 cm
->DeleteAllCreatedBetweenForHostAsync(
200 delete_begin
, delete_end
, url
,
201 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
202 base::Unretained(&callback
)));
204 EXPECT_TRUE(callback
.did_run());
205 return callback
.result();
208 int DeleteAllForHost(CookieMonster
* cm
, const GURL
& url
) {
210 ResultSavingCookieCallback
<int> callback
;
211 cm
->DeleteAllForHostAsync(url
,
212 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
213 base::Unretained(&callback
)));
215 EXPECT_TRUE(callback
.did_run());
216 return callback
.result();
219 bool DeleteCanonicalCookie(CookieMonster
* cm
, const CanonicalCookie
& cookie
) {
221 ResultSavingCookieCallback
<bool> callback
;
222 cm
->DeleteCanonicalCookieAsync(
223 cookie
, base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
224 base::Unretained(&callback
)));
226 EXPECT_TRUE(callback
.did_run());
227 return callback
.result();
230 // Helper for DeleteAllForHost test; repopulates CM with same layout
232 void PopulateCmForDeleteAllForHost(scoped_refptr
<CookieMonster
> cm
) {
233 GURL
url_top_level_domain_plus_1(kTopLevelDomainPlus1
);
234 GURL
url_top_level_domain_plus_2(kTopLevelDomainPlus2
);
235 GURL
url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure
);
236 GURL
url_top_level_domain_plus_3(kTopLevelDomainPlus3
);
237 GURL
url_other(kOtherDomain
);
241 // Static population for probe:
242 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
243 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
244 // * http_only cookie (w.c.b.a)
245 // * first-party cookie (w.c.b.a)
246 // * Two secure cookies (.c.b.a, w.c.b.a)
247 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
248 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
251 EXPECT_TRUE(this->SetCookieWithDetails(
252 cm
.get(), url_top_level_domain_plus_1
, "dom_1", "X", ".harvard.edu",
253 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
254 EXPECT_TRUE(this->SetCookieWithDetails(
255 cm
.get(), url_top_level_domain_plus_2
, "dom_2", "X",
256 ".math.harvard.edu", "/", base::Time(), false, false, false,
257 COOKIE_PRIORITY_DEFAULT
));
258 EXPECT_TRUE(this->SetCookieWithDetails(
259 cm
.get(), url_top_level_domain_plus_3
, "dom_3", "X",
260 ".bourbaki.math.harvard.edu", "/", base::Time(), false, false, false,
261 COOKIE_PRIORITY_DEFAULT
));
264 EXPECT_TRUE(this->SetCookieWithDetails(
265 cm
.get(), url_top_level_domain_plus_1
, "host_1", "X", std::string(),
266 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
267 EXPECT_TRUE(this->SetCookieWithDetails(
268 cm
.get(), url_top_level_domain_plus_2
, "host_2", "X", std::string(),
269 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
270 EXPECT_TRUE(this->SetCookieWithDetails(
271 cm
.get(), url_top_level_domain_plus_3
, "host_3", "X", std::string(),
272 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
275 EXPECT_TRUE(this->SetCookieWithDetails(
276 cm
.get(), url_top_level_domain_plus_2
, "httpo_check", "x",
277 std::string(), "/", base::Time(), false, true, false,
278 COOKIE_PRIORITY_DEFAULT
));
280 // first-party cookie
281 EXPECT_TRUE(this->SetCookieWithDetails(
282 cm
.get(), url_top_level_domain_plus_2
, "firstp_check", "x",
283 std::string(), "/", base::Time(), false, false, true,
284 COOKIE_PRIORITY_DEFAULT
));
287 EXPECT_TRUE(this->SetCookieWithDetails(
288 cm
.get(), url_top_level_domain_plus_2_secure
, "sec_dom", "X",
289 ".math.harvard.edu", "/", base::Time(), true, false, false,
290 COOKIE_PRIORITY_DEFAULT
));
291 EXPECT_TRUE(this->SetCookieWithDetails(
292 cm
.get(), url_top_level_domain_plus_2_secure
, "sec_host", "X",
293 std::string(), "/", base::Time(), true, false, false,
294 COOKIE_PRIORITY_DEFAULT
));
296 // Domain path cookies
297 EXPECT_TRUE(this->SetCookieWithDetails(
298 cm
.get(), url_top_level_domain_plus_2
, "dom_path_1", "X",
299 ".math.harvard.edu", "/dir1", base::Time(), false, false, false,
300 COOKIE_PRIORITY_DEFAULT
));
301 EXPECT_TRUE(this->SetCookieWithDetails(
302 cm
.get(), url_top_level_domain_plus_2
, "dom_path_2", "X",
303 ".math.harvard.edu", "/dir1/dir2", base::Time(), false, false, false,
304 COOKIE_PRIORITY_DEFAULT
));
307 EXPECT_TRUE(this->SetCookieWithDetails(
308 cm
.get(), url_top_level_domain_plus_2
, "host_path_1", "X",
309 std::string(), "/dir1", base::Time(), false, false, false,
310 COOKIE_PRIORITY_DEFAULT
));
311 EXPECT_TRUE(this->SetCookieWithDetails(
312 cm
.get(), url_top_level_domain_plus_2
, "host_path_2", "X",
313 std::string(), "/dir1/dir2", base::Time(), false, false, false,
314 COOKIE_PRIORITY_DEFAULT
));
316 EXPECT_EQ(14U, this->GetAllCookies(cm
.get()).size());
319 Time
GetFirstCookieAccessDate(CookieMonster
* cm
) {
320 const CookieList
all_cookies(this->GetAllCookies(cm
));
321 return all_cookies
.front().LastAccessDate();
324 bool FindAndDeleteCookie(CookieMonster
* cm
,
325 const std::string
& domain
,
326 const std::string
& name
) {
327 CookieList cookies
= this->GetAllCookies(cm
);
328 for (CookieList::iterator it
= cookies
.begin(); it
!= cookies
.end(); ++it
)
329 if (it
->Domain() == domain
&& it
->Name() == name
)
330 return this->DeleteCanonicalCookie(cm
, *it
);
334 int CountInString(const std::string
& str
, char c
) {
335 return std::count(str
.begin(), str
.end(), c
);
338 void TestHostGarbageCollectHelper() {
339 int domain_max_cookies
= CookieMonster::kDomainMaxCookies
;
340 int domain_purge_cookies
= CookieMonster::kDomainPurgeCookies
;
341 const int more_than_enough_cookies
=
342 (domain_max_cookies
+ domain_purge_cookies
) * 2;
343 // Add a bunch of cookies on a single host, should purge them.
345 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
346 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
347 std::string cookie
= base::StringPrintf("a%03d=b", i
);
348 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie
));
349 std::string cookies
= this->GetCookies(cm
.get(), url_google_
);
350 // Make sure we find it in the cookies.
351 EXPECT_NE(cookies
.find(cookie
), std::string::npos
);
352 // Count the number of cookies.
353 EXPECT_LE(CountInString(cookies
, '='), domain_max_cookies
);
357 // Add a bunch of cookies on multiple hosts within a single eTLD.
358 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
359 // between them. We shouldn't go above kDomainMaxCookies for both together.
360 GURL
url_google_specific(kUrlGoogleSpecific
);
362 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
363 for (int i
= 0; i
< more_than_enough_cookies
; ++i
) {
364 std::string cookie_general
= base::StringPrintf("a%03d=b", i
);
365 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, cookie_general
));
366 std::string cookie_specific
= base::StringPrintf("c%03d=b", i
);
367 EXPECT_TRUE(SetCookie(cm
.get(), url_google_specific
, cookie_specific
));
368 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
369 EXPECT_NE(cookies_general
.find(cookie_general
), std::string::npos
);
370 std::string cookies_specific
=
371 this->GetCookies(cm
.get(), url_google_specific
);
372 EXPECT_NE(cookies_specific
.find(cookie_specific
), std::string::npos
);
373 EXPECT_LE((CountInString(cookies_general
, '=') +
374 CountInString(cookies_specific
, '=')),
377 // After all this, there should be at least
378 // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
379 std::string cookies_general
= this->GetCookies(cm
.get(), url_google_
);
380 std::string cookies_specific
=
381 this->GetCookies(cm
.get(), url_google_specific
);
382 int total_cookies
= (CountInString(cookies_general
, '=') +
383 CountInString(cookies_specific
, '='));
384 EXPECT_GE(total_cookies
, domain_max_cookies
- domain_purge_cookies
);
385 EXPECT_LE(total_cookies
, domain_max_cookies
);
389 CookiePriority
CharToPriority(char ch
) {
392 return COOKIE_PRIORITY_LOW
;
394 return COOKIE_PRIORITY_MEDIUM
;
396 return COOKIE_PRIORITY_HIGH
;
399 return COOKIE_PRIORITY_DEFAULT
;
402 // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
403 // priorities specified by |coded_priority_str|, and tests priority-aware
404 // domain cookie eviction.
405 // |coded_priority_str| specifies a run-length-encoded string of priorities.
406 // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
407 // from least- to most-recently accessed) insertion of 2 medium-priority
408 // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4
409 // high-priority cookies.
410 // Within each priority, only the least-accessed cookies should be evicted.
411 // Thus, to describe expected suriving cookies, it suffices to specify the
412 // expected population of surviving cookies per priority, i.e.,
413 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
414 void TestPriorityCookieCase(CookieMonster
* cm
,
415 const std::string
& coded_priority_str
,
416 size_t expected_low_count
,
417 size_t expected_medium_count
,
418 size_t expected_high_count
) {
420 int next_cookie_id
= 0;
421 std::vector
<CookiePriority
> priority_list
;
422 std::vector
<int> id_list
[3]; // Indexed by CookiePriority.
424 // Parse |coded_priority_str| and add cookies.
425 std::vector
<std::string
> priority_tok_list
;
426 base::SplitString(coded_priority_str
, ' ', &priority_tok_list
);
427 for (std::vector
<std::string
>::iterator it
= priority_tok_list
.begin();
428 it
!= priority_tok_list
.end(); ++it
) {
429 size_t len
= it
->length();
431 // Take last character as priority.
432 CookiePriority priority
= CharToPriority((*it
)[len
- 1]);
433 std::string priority_str
= CookiePriorityToString(priority
);
434 // The rest of the string (possibly empty) specifies repetition.
437 bool result
= base::StringToInt(
438 base::StringPiece(it
->begin(), it
->end() - 1), &rep
);
441 for (; rep
> 0; --rep
, ++next_cookie_id
) {
442 std::string cookie
= base::StringPrintf(
443 "a%d=b;priority=%s", next_cookie_id
, priority_str
.c_str());
444 EXPECT_TRUE(SetCookie(cm
, url_google_
, cookie
));
445 priority_list
.push_back(priority
);
446 id_list
[priority
].push_back(next_cookie_id
);
450 int num_cookies
= static_cast<int>(priority_list
.size());
451 std::vector
<int> surviving_id_list
[3]; // Indexed by CookiePriority.
453 // Parse the list of cookies
454 std::string cookie_str
= this->GetCookies(cm
, url_google_
);
455 std::vector
<std::string
> cookie_tok_list
;
456 base::SplitString(cookie_str
, ';', &cookie_tok_list
);
457 for (std::vector
<std::string
>::iterator it
= cookie_tok_list
.begin();
458 it
!= cookie_tok_list
.end(); ++it
) {
459 // Assuming *it is "a#=b", so extract and parse "#" portion.
461 bool result
= base::StringToInt(
462 base::StringPiece(it
->begin() + 1, it
->end() - 2), &id
);
465 DCHECK_LT(id
, num_cookies
);
466 surviving_id_list
[priority_list
[id
]].push_back(id
);
469 // Validate each priority.
470 size_t expected_count
[3] = {
471 expected_low_count
, expected_medium_count
, expected_high_count
};
472 for (int i
= 0; i
< 3; ++i
) {
473 DCHECK_LE(surviving_id_list
[i
].size(), id_list
[i
].size());
474 EXPECT_EQ(expected_count
[i
], surviving_id_list
[i
].size());
475 // Verify that the remaining cookies are the most recent among those
476 // with the same priorities.
477 if (expected_count
[i
] == surviving_id_list
[i
].size()) {
478 std::sort(surviving_id_list
[i
].begin(), surviving_id_list
[i
].end());
479 EXPECT_TRUE(std::equal(surviving_id_list
[i
].begin(),
480 surviving_id_list
[i
].end(),
481 id_list
[i
].end() - expected_count
[i
]));
486 void TestPriorityAwareGarbageCollectHelper() {
487 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
488 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies
);
489 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies
-
490 CookieMonster::kDomainPurgeCookies
);
491 DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow
);
492 DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium
);
493 DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh
);
495 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
497 // Each test case adds 181 cookies, so 31 cookies are evicted.
498 // Cookie same priority, repeated for each priority.
499 TestPriorityCookieCase(cm
.get(), "181L", 150U, 0U, 0U);
500 TestPriorityCookieCase(cm
.get(), "181M", 0U, 150U, 0U);
501 TestPriorityCookieCase(cm
.get(), "181H", 0U, 0U, 150U);
503 // Pairwise scenarios.
504 // Round 1 => none; round2 => 31M; round 3 => none.
505 TestPriorityCookieCase(cm
.get(), "10H 171M", 0U, 140U, 10U);
506 // Round 1 => 10L; round2 => 21M; round 3 => none.
507 TestPriorityCookieCase(cm
.get(), "141M 40L", 30U, 120U, 0U);
508 // Round 1 => none; round2 => none; round 3 => 31H.
509 TestPriorityCookieCase(cm
.get(), "101H 80M", 0U, 80U, 70U);
511 // For {low, medium} priorities right on quota, different orders.
512 // Round 1 => 1L; round 2 => none, round3 => 30L.
513 TestPriorityCookieCase(cm
.get(), "31L 50M 100H", 0U, 50U, 100U);
514 // Round 1 => none; round 2 => 1M, round3 => 30M.
515 TestPriorityCookieCase(cm
.get(), "51M 100H 30L", 30U, 20U, 100U);
516 // Round 1 => none; round 2 => none; round3 => 31H.
517 TestPriorityCookieCase(cm
.get(), "101H 50M 30L", 30U, 50U, 70U);
519 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
520 TestPriorityCookieCase(cm
.get(), "81H 60M 40L", 30U, 50U, 70U);
522 // More complex scenarios.
523 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
524 TestPriorityCookieCase(cm
.get(), "21H 60M 40L 60H", 30U, 50U, 70U);
525 // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
526 TestPriorityCookieCase(cm
.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U,
528 // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
529 TestPriorityCookieCase(cm
.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U);
530 // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
531 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U);
532 // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
533 TestPriorityCookieCase(cm
.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U);
536 // Function for creating a CM with a number of cookies in it,
537 // no store (and hence no ability to affect access time).
538 CookieMonster
* CreateMonsterForGC(int num_cookies
) {
539 CookieMonster
* cm(new CookieMonster(NULL
, NULL
));
540 for (int i
= 0; i
< num_cookies
; i
++) {
541 SetCookie(cm
, GURL(base::StringPrintf("http://h%05d.izzle", i
)), "a=1");
547 // TODO(erikwright): Replace the other callbacks and synchronous helper methods
548 // in this test suite with these Mocks.
549 template <typename T
, typename C
>
550 class MockCookieCallback
{
553 return base::Bind(&T::Invoke
, base::Unretained(static_cast<T
*>(this)));
557 class MockGetCookiesCallback
558 : public MockCookieCallback
<MockGetCookiesCallback
,
559 CookieStore::GetCookiesCallback
> {
561 MOCK_METHOD1(Invoke
, void(const std::string
& cookies
));
564 class MockSetCookiesCallback
565 : public MockCookieCallback
<MockSetCookiesCallback
,
566 CookieStore::SetCookiesCallback
> {
568 MOCK_METHOD1(Invoke
, void(bool success
));
571 class MockClosure
: public MockCookieCallback
<MockClosure
, base::Closure
> {
573 MOCK_METHOD0(Invoke
, void(void));
576 class MockGetCookieListCallback
577 : public MockCookieCallback
<MockGetCookieListCallback
,
578 CookieMonster::GetCookieListCallback
> {
580 MOCK_METHOD1(Invoke
, void(const CookieList
& cookies
));
583 class MockDeleteCallback
584 : public MockCookieCallback
<MockDeleteCallback
,
585 CookieMonster::DeleteCallback
> {
587 MOCK_METHOD1(Invoke
, void(int num_deleted
));
590 class MockDeleteCookieCallback
591 : public MockCookieCallback
<MockDeleteCookieCallback
,
592 CookieMonster::DeleteCookieCallback
> {
594 MOCK_METHOD1(Invoke
, void(bool success
));
597 struct CookiesInputInfo
{
599 const std::string name
;
600 const std::string value
;
601 const std::string domain
;
602 const std::string path
;
603 const base::Time expiration_time
;
606 bool first_party_only
;
607 CookiePriority priority
;
610 ACTION(QuitCurrentMessageLoop
) {
611 base::MessageLoop::current()->PostTask(FROM_HERE
,
612 base::MessageLoop::QuitClosure());
615 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
616 // rename these, removing the 'Action' suffix.
617 ACTION_P4(DeleteCookieAction
, cookie_monster
, url
, name
, callback
) {
618 cookie_monster
->DeleteCookieAsync(url
, name
, callback
->AsCallback());
620 ACTION_P3(GetCookiesAction
, cookie_monster
, url
, callback
) {
621 cookie_monster
->GetCookiesWithOptionsAsync(url
, CookieOptions(),
622 callback
->AsCallback());
624 ACTION_P4(SetCookieAction
, cookie_monster
, url
, cookie_line
, callback
) {
625 cookie_monster
->SetCookieWithOptionsAsync(url
, cookie_line
, CookieOptions(),
626 callback
->AsCallback());
628 ACTION_P4(DeleteAllCreatedBetweenAction
,
633 cookie_monster
->DeleteAllCreatedBetweenAsync(delete_begin
, delete_end
,
634 callback
->AsCallback());
636 ACTION_P3(SetCookieWithDetailsAction
, cookie_monster
, cc
, callback
) {
637 cookie_monster
->SetCookieWithDetailsAsync(
638 cc
.url
, cc
.name
, cc
.value
, cc
.domain
, cc
.path
, cc
.expiration_time
,
639 cc
.secure
, cc
.http_only
, cc
.first_party_only
, cc
.priority
,
640 callback
->AsCallback());
643 ACTION_P2(GetAllCookiesAction
, cookie_monster
, callback
) {
644 cookie_monster
->GetAllCookiesAsync(callback
->AsCallback());
647 ACTION_P3(DeleteAllForHostAction
, cookie_monster
, url
, callback
) {
648 cookie_monster
->DeleteAllForHostAsync(url
, callback
->AsCallback());
651 ACTION_P3(DeleteCanonicalCookieAction
, cookie_monster
, cookie
, callback
) {
652 cookie_monster
->DeleteCanonicalCookieAsync(cookie
, callback
->AsCallback());
655 ACTION_P2(DeleteAllAction
, cookie_monster
, callback
) {
656 cookie_monster
->DeleteAllAsync(callback
->AsCallback());
659 ACTION_P3(GetAllCookiesForUrlWithOptionsAction
, cookie_monster
, url
, callback
) {
660 cookie_monster
->GetAllCookiesForURLWithOptionsAsync(url
, CookieOptions(),
661 callback
->AsCallback());
664 ACTION_P3(GetAllCookiesForUrlAction
, cookie_monster
, url
, callback
) {
665 cookie_monster
->GetAllCookiesForURLAsync(url
, callback
->AsCallback());
668 ACTION_P(PushCallbackAction
, callback_vector
) {
669 callback_vector
->push(arg1
);
672 ACTION_P2(DeleteSessionCookiesAction
, cookie_monster
, callback
) {
673 cookie_monster
->DeleteSessionCookiesAsync(callback
->AsCallback());
678 // This test suite verifies the task deferral behaviour of the CookieMonster.
679 // Specifically, for each asynchronous method, verify that:
680 // 1. invoking it on an uninitialized cookie store causes the store to begin
681 // chain-loading its backing data or loading data for a specific domain key
683 // 2. The initial invocation does not complete until the loading completes.
684 // 3. Invocations after the loading has completed complete immediately.
685 class DeferredCookieTaskTest
: public CookieMonsterTest
{
687 DeferredCookieTaskTest() {
688 persistent_store_
= new NewMockPersistentCookieStore();
689 cookie_monster_
= new CookieMonster(persistent_store_
.get(), NULL
);
692 // Defines a cookie to be returned from PersistentCookieStore::Load
693 void DeclareLoadedCookie(const std::string
& key
,
694 const std::string
& cookie_line
,
695 const base::Time
& creation_time
) {
696 AddCookieToList(key
, cookie_line
, creation_time
, &loaded_cookies_
);
699 // Runs the message loop, waiting until PersistentCookieStore::Load is called.
700 // Call CompleteLoadingAndWait to cause the load to complete.
701 void WaitForLoadCall() {
704 // Verify that PeristentStore::Load was called.
705 testing::Mock::VerifyAndClear(persistent_store_
.get());
708 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
709 // and PersistentCookieStore::Load completion callback and waits
710 // until the message loop is quit.
711 void CompleteLoadingAndWait() {
712 while (!loaded_for_key_callbacks_
.empty()) {
713 loaded_for_key_callbacks_
.front().Run(loaded_cookies_
);
714 loaded_cookies_
.clear();
715 loaded_for_key_callbacks_
.pop();
718 loaded_callback_
.Run(loaded_cookies_
);
722 // Performs the provided action, expecting it to cause a call to
723 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call
725 void BeginWith(testing::Action
<void(void)> action
) {
726 EXPECT_CALL(*this, Begin()).WillOnce(action
);
731 void BeginWithForDomainKey(std::string key
,
732 testing::Action
<void(void)> action
) {
733 EXPECT_CALL(*this, Begin()).WillOnce(action
);
735 ExpectLoadForKeyCall(key
, false);
739 // Declares an expectation that PersistentCookieStore::Load will be called,
740 // saving the provided callback and sending a quit to the message loop.
741 void ExpectLoadCall() {
742 EXPECT_CALL(*persistent_store_
.get(), Load(testing::_
))
743 .WillOnce(testing::DoAll(testing::SaveArg
<0>(&loaded_callback_
),
744 QuitCurrentMessageLoop()));
747 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
748 // will be called, saving the provided callback and sending a quit to the
750 void ExpectLoadForKeyCall(std::string key
, bool quit_queue
) {
752 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
754 testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_
),
755 QuitCurrentMessageLoop()));
757 EXPECT_CALL(*persistent_store_
.get(), LoadCookiesForKey(key
, testing::_
))
758 .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_
));
761 // Invokes the initial action.
762 MOCK_METHOD0(Begin
, void(void));
764 // Returns the CookieMonster instance under test.
765 CookieMonster
& cookie_monster() { return *cookie_monster_
.get(); }
768 // Declares that mock expectations in this test suite are strictly ordered.
769 testing::InSequence in_sequence_
;
770 // Holds cookies to be returned from PersistentCookieStore::Load or
771 // PersistentCookieStore::LoadCookiesForKey.
772 std::vector
<CanonicalCookie
*> loaded_cookies_
;
773 // Stores the callback passed from the CookieMonster to the
774 // PersistentCookieStore::Load
775 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_
;
776 // Stores the callback passed from the CookieMonster to the
777 // PersistentCookieStore::LoadCookiesForKey
778 std::queue
<CookieMonster::PersistentCookieStore::LoadedCallback
>
779 loaded_for_key_callbacks_
;
781 // Stores the CookieMonster under test.
782 scoped_refptr
<CookieMonster
> cookie_monster_
;
783 // Stores the mock PersistentCookieStore.
784 scoped_refptr
<NewMockPersistentCookieStore
> persistent_store_
;
787 TEST_F(DeferredCookieTaskTest
, DeferredGetCookies
) {
788 DeclareLoadedCookie("www.google.izzle",
789 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
790 Time::Now() + TimeDelta::FromDays(3));
792 MockGetCookiesCallback get_cookies_callback
;
794 BeginWithForDomainKey(
796 GetCookiesAction(&cookie_monster(), url_google_
, &get_cookies_callback
));
800 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
801 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_
,
802 &get_cookies_callback
));
803 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
804 .WillOnce(QuitCurrentMessageLoop());
806 CompleteLoadingAndWait();
809 TEST_F(DeferredCookieTaskTest
, DeferredSetCookie
) {
810 MockSetCookiesCallback set_cookies_callback
;
812 BeginWithForDomainKey("google.izzle",
813 SetCookieAction(&cookie_monster(), url_google_
, "A=B",
814 &set_cookies_callback
));
818 EXPECT_CALL(set_cookies_callback
, Invoke(true))
819 .WillOnce(SetCookieAction(&cookie_monster(), url_google_
, "X=Y",
820 &set_cookies_callback
));
821 EXPECT_CALL(set_cookies_callback
, Invoke(true))
822 .WillOnce(QuitCurrentMessageLoop());
824 CompleteLoadingAndWait();
827 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCookie
) {
828 MockClosure delete_cookie_callback
;
830 BeginWithForDomainKey("google.izzle",
831 DeleteCookieAction(&cookie_monster(), url_google_
, "A",
832 &delete_cookie_callback
));
836 EXPECT_CALL(delete_cookie_callback
, Invoke())
837 .WillOnce(DeleteCookieAction(&cookie_monster(), url_google_
, "X",
838 &delete_cookie_callback
));
839 EXPECT_CALL(delete_cookie_callback
, Invoke())
840 .WillOnce(QuitCurrentMessageLoop());
842 CompleteLoadingAndWait();
845 TEST_F(DeferredCookieTaskTest
, DeferredSetCookieWithDetails
) {
846 MockSetCookiesCallback set_cookies_callback
;
848 CookiesInputInfo cookie_info
= {url_google_foo_
,
857 COOKIE_PRIORITY_DEFAULT
};
858 BeginWithForDomainKey(
859 "google.izzle", SetCookieWithDetailsAction(&cookie_monster(), cookie_info
,
860 &set_cookies_callback
));
864 CookiesInputInfo cookie_info_exp
= {url_google_foo_
,
873 COOKIE_PRIORITY_DEFAULT
};
874 EXPECT_CALL(set_cookies_callback
, Invoke(true))
875 .WillOnce(SetCookieWithDetailsAction(&cookie_monster(), cookie_info_exp
,
876 &set_cookies_callback
));
877 EXPECT_CALL(set_cookies_callback
, Invoke(true))
878 .WillOnce(QuitCurrentMessageLoop());
880 CompleteLoadingAndWait();
883 TEST_F(DeferredCookieTaskTest
, DeferredGetAllCookies
) {
884 DeclareLoadedCookie("www.google.izzle",
885 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
886 Time::Now() + TimeDelta::FromDays(3));
888 MockGetCookieListCallback get_cookie_list_callback
;
890 BeginWith(GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback
));
894 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
896 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback
));
897 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
898 .WillOnce(QuitCurrentMessageLoop());
900 CompleteLoadingAndWait();
903 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlCookies
) {
904 DeclareLoadedCookie("www.google.izzle",
905 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
906 Time::Now() + TimeDelta::FromDays(3));
908 MockGetCookieListCallback get_cookie_list_callback
;
910 BeginWithForDomainKey(
911 "google.izzle", GetAllCookiesForUrlAction(&cookie_monster(), url_google_
,
912 &get_cookie_list_callback
));
916 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
917 .WillOnce(GetAllCookiesForUrlAction(&cookie_monster(), url_google_
,
918 &get_cookie_list_callback
));
919 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
920 .WillOnce(QuitCurrentMessageLoop());
922 CompleteLoadingAndWait();
925 TEST_F(DeferredCookieTaskTest
, DeferredGetAllForUrlWithOptionsCookies
) {
926 DeclareLoadedCookie("www.google.izzle",
927 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
928 Time::Now() + TimeDelta::FromDays(3));
930 MockGetCookieListCallback get_cookie_list_callback
;
932 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
933 &cookie_monster(), url_google_
,
934 &get_cookie_list_callback
));
938 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
939 .WillOnce(GetAllCookiesForUrlWithOptionsAction(
940 &cookie_monster(), url_google_
, &get_cookie_list_callback
));
941 EXPECT_CALL(get_cookie_list_callback
, Invoke(testing::_
))
942 .WillOnce(QuitCurrentMessageLoop());
944 CompleteLoadingAndWait();
947 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCookies
) {
948 MockDeleteCallback delete_callback
;
950 BeginWith(DeleteAllAction(&cookie_monster(), &delete_callback
));
954 EXPECT_CALL(delete_callback
, Invoke(false))
955 .WillOnce(DeleteAllAction(&cookie_monster(), &delete_callback
));
956 EXPECT_CALL(delete_callback
, Invoke(false))
957 .WillOnce(QuitCurrentMessageLoop());
959 CompleteLoadingAndWait();
962 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllCreatedBetweenCookies
) {
963 MockDeleteCallback delete_callback
;
965 BeginWith(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
966 base::Time::Now(), &delete_callback
));
970 EXPECT_CALL(delete_callback
, Invoke(false))
971 .WillOnce(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
974 EXPECT_CALL(delete_callback
, Invoke(false))
975 .WillOnce(QuitCurrentMessageLoop());
977 CompleteLoadingAndWait();
980 TEST_F(DeferredCookieTaskTest
, DeferredDeleteAllForHostCookies
) {
981 MockDeleteCallback delete_callback
;
983 BeginWithForDomainKey(
985 DeleteAllForHostAction(&cookie_monster(), url_google_
, &delete_callback
));
989 EXPECT_CALL(delete_callback
, Invoke(false))
990 .WillOnce(DeleteAllForHostAction(&cookie_monster(), url_google_
,
992 EXPECT_CALL(delete_callback
, Invoke(false))
993 .WillOnce(QuitCurrentMessageLoop());
995 CompleteLoadingAndWait();
998 TEST_F(DeferredCookieTaskTest
, DeferredDeleteCanonicalCookie
) {
999 std::vector
<CanonicalCookie
*> cookies
;
1000 CanonicalCookie cookie
=
1001 BuildCanonicalCookie("www.google.com", "X=1; path=/", base::Time::Now());
1003 MockDeleteCookieCallback delete_cookie_callback
;
1005 BeginWith(DeleteCanonicalCookieAction(&cookie_monster(), cookie
,
1006 &delete_cookie_callback
));
1010 EXPECT_CALL(delete_cookie_callback
, Invoke(false))
1011 .WillOnce(DeleteCanonicalCookieAction(&cookie_monster(), cookie
,
1012 &delete_cookie_callback
));
1013 EXPECT_CALL(delete_cookie_callback
, Invoke(false))
1014 .WillOnce(QuitCurrentMessageLoop());
1016 CompleteLoadingAndWait();
1019 TEST_F(DeferredCookieTaskTest
, DeferredDeleteSessionCookies
) {
1020 MockDeleteCallback delete_callback
;
1022 BeginWith(DeleteSessionCookiesAction(&cookie_monster(), &delete_callback
));
1026 EXPECT_CALL(delete_callback
, Invoke(false))
1028 DeleteSessionCookiesAction(&cookie_monster(), &delete_callback
));
1029 EXPECT_CALL(delete_callback
, Invoke(false))
1030 .WillOnce(QuitCurrentMessageLoop());
1032 CompleteLoadingAndWait();
1035 // Verify that a series of queued tasks are executed in order upon loading of
1036 // the backing store and that new tasks received while the queued tasks are
1037 // being dispatched go to the end of the queue.
1038 TEST_F(DeferredCookieTaskTest
, DeferredTaskOrder
) {
1039 DeclareLoadedCookie("www.google.izzle",
1040 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1041 Time::Now() + TimeDelta::FromDays(3));
1043 MockGetCookiesCallback get_cookies_callback
;
1044 MockSetCookiesCallback set_cookies_callback
;
1045 MockGetCookiesCallback get_cookies_callback_deferred
;
1047 EXPECT_CALL(*this, Begin())
1048 .WillOnce(testing::DoAll(GetCookiesAction(&cookie_monster(), url_google_
,
1049 &get_cookies_callback
),
1050 SetCookieAction(&cookie_monster(), url_google_
,
1051 "A=B", &set_cookies_callback
)));
1053 ExpectLoadForKeyCall("google.izzle", false);
1057 EXPECT_CALL(get_cookies_callback
, Invoke("X=1"))
1058 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_
,
1059 &get_cookies_callback_deferred
));
1060 EXPECT_CALL(set_cookies_callback
, Invoke(true));
1061 EXPECT_CALL(get_cookies_callback_deferred
, Invoke("A=B; X=1"))
1062 .WillOnce(QuitCurrentMessageLoop());
1064 CompleteLoadingAndWait();
1067 TEST_F(CookieMonsterTest
, TestCookieDeleteAll
) {
1068 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1069 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1070 CookieOptions options
;
1071 options
.set_include_httponly();
1073 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
1074 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1077 SetCookieWithOptions(cm
.get(), url_google_
, "C=D; httponly", options
));
1078 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1080 EXPECT_EQ(2, DeleteAll(cm
.get()));
1081 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1082 EXPECT_EQ(0u, store
->commands().size());
1084 // Create a persistent cookie.
1085 EXPECT_TRUE(SetCookie(
1086 cm
.get(), url_google_
,
1087 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1088 ASSERT_EQ(1u, store
->commands().size());
1089 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1091 EXPECT_EQ(1, DeleteAll(cm
.get())); // sync_to_store = true.
1092 ASSERT_EQ(2u, store
->commands().size());
1093 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1095 EXPECT_EQ("", GetCookiesWithOptions(cm
.get(), url_google_
, options
));
1098 TEST_F(CookieMonsterTest
, TestCookieDeleteAllCreatedBetweenTimestamps
) {
1099 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1100 Time now
= Time::Now();
1102 // Nothing has been added so nothing should be deleted.
1103 EXPECT_EQ(0, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99),
1106 // Create 3 cookies with creation date of today, yesterday and the day before.
1107 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-0=Now", now
));
1108 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-1=Yesterday",
1109 now
- TimeDelta::FromDays(1)));
1110 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-2=DayBefore",
1111 now
- TimeDelta::FromDays(2)));
1112 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-3=ThreeDays",
1113 now
- TimeDelta::FromDays(3)));
1114 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "T-7=LastWeek",
1115 now
- TimeDelta::FromDays(7)));
1117 // Try to delete threedays and the daybefore.
1118 EXPECT_EQ(2, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(3),
1119 now
- TimeDelta::FromDays(1)));
1121 // Try to delete yesterday, also make sure that delete_end is not
1124 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(2), now
));
1126 // Make sure the delete_begin is inclusive.
1128 1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(7), now
));
1130 // Delete the last (now) item.
1131 EXPECT_EQ(1, DeleteAllCreatedBetween(cm
.get(), Time(), Time()));
1133 // Really make sure everything is gone.
1134 EXPECT_EQ(0, DeleteAll(cm
.get()));
1137 static const int kAccessDelayMs
= kLastAccessThresholdMilliseconds
+ 20;
1139 TEST_F(CookieMonsterTest
, TestLastAccess
) {
1140 scoped_refptr
<CookieMonster
> cm(
1141 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1143 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1144 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1146 // Reading the cookie again immediately shouldn't update the access date,
1147 // since we're inside the threshold.
1148 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1149 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1151 // Reading after a short wait should update the access date.
1152 base::PlatformThread::Sleep(
1153 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1154 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
1155 EXPECT_FALSE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1158 TEST_F(CookieMonsterTest
, TestHostGarbageCollection
) {
1159 TestHostGarbageCollectHelper();
1162 TEST_F(CookieMonsterTest
, TestPriorityAwareGarbageCollection
) {
1163 TestPriorityAwareGarbageCollectHelper();
1166 TEST_F(CookieMonsterTest
, TestDeleteSingleCookie
) {
1167 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1169 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1170 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1171 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1172 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1174 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1175 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1177 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1178 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1181 TEST_F(CookieMonsterTest
, SetCookieableSchemes
) {
1182 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1183 scoped_refptr
<CookieMonster
> cm_foo(new CookieMonster(NULL
, NULL
));
1185 // Only cm_foo should allow foo:// cookies.
1186 const char* const kSchemes
[] = {"foo"};
1187 cm_foo
->SetCookieableSchemes(kSchemes
, 1);
1189 GURL
foo_url("foo://host/path");
1190 GURL
http_url("http://host/path");
1192 EXPECT_TRUE(SetCookie(cm
.get(), http_url
, "x=1"));
1193 EXPECT_FALSE(SetCookie(cm
.get(), foo_url
, "x=1"));
1194 EXPECT_TRUE(SetCookie(cm_foo
.get(), foo_url
, "x=1"));
1195 EXPECT_FALSE(SetCookie(cm_foo
.get(), http_url
, "x=1"));
1198 TEST_F(CookieMonsterTest
, GetAllCookiesForURL
) {
1199 scoped_refptr
<CookieMonster
> cm(
1200 new CookieMonster(NULL
, NULL
, kLastAccessThresholdMilliseconds
));
1202 // Create an httponly cookie.
1203 CookieOptions options
;
1204 options
.set_include_httponly();
1207 SetCookieWithOptions(cm
.get(), url_google_
, "A=B; httponly", options
));
1208 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
,
1209 "C=D; domain=.google.izzle", options
));
1210 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_secure_
,
1211 "E=F; domain=.google.izzle; secure",
1214 const Time
last_access_date(GetFirstCookieAccessDate(cm
.get()));
1216 base::PlatformThread::Sleep(
1217 base::TimeDelta::FromMilliseconds(kAccessDelayMs
));
1219 // Check cookies for url.
1220 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
1221 CookieList::iterator it
= cookies
.begin();
1223 ASSERT_TRUE(it
!= cookies
.end());
1224 EXPECT_EQ("www.google.izzle", it
->Domain());
1225 EXPECT_EQ("A", it
->Name());
1227 ASSERT_TRUE(++it
!= cookies
.end());
1228 EXPECT_EQ(".google.izzle", it
->Domain());
1229 EXPECT_EQ("C", it
->Name());
1231 ASSERT_TRUE(++it
== cookies
.end());
1233 // Check cookies for url excluding http-only cookies.
1235 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, CookieOptions());
1236 it
= cookies
.begin();
1238 ASSERT_TRUE(it
!= cookies
.end());
1239 EXPECT_EQ(".google.izzle", it
->Domain());
1240 EXPECT_EQ("C", it
->Name());
1242 ASSERT_TRUE(++it
== cookies
.end());
1244 // Test secure cookies.
1245 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1246 it
= cookies
.begin();
1248 ASSERT_TRUE(it
!= cookies
.end());
1249 EXPECT_EQ("www.google.izzle", it
->Domain());
1250 EXPECT_EQ("A", it
->Name());
1252 ASSERT_TRUE(++it
!= cookies
.end());
1253 EXPECT_EQ(".google.izzle", it
->Domain());
1254 EXPECT_EQ("C", it
->Name());
1256 ASSERT_TRUE(++it
!= cookies
.end());
1257 EXPECT_EQ(".google.izzle", it
->Domain());
1258 EXPECT_EQ("E", it
->Name());
1260 ASSERT_TRUE(++it
== cookies
.end());
1262 // Reading after a short wait should not update the access date.
1263 EXPECT_TRUE(last_access_date
== GetFirstCookieAccessDate(cm
.get()));
1266 TEST_F(CookieMonsterTest
, GetAllCookiesForURLPathMatching
) {
1267 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1268 CookieOptions options
;
1270 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_foo_
, "A=B; path=/foo;",
1272 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_bar_
, "C=D; path=/bar;",
1274 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "E=F;", options
));
1276 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1277 CookieList::iterator it
= cookies
.begin();
1279 ASSERT_TRUE(it
!= cookies
.end());
1280 EXPECT_EQ("A", it
->Name());
1281 EXPECT_EQ("/foo", it
->Path());
1283 ASSERT_TRUE(++it
!= cookies
.end());
1284 EXPECT_EQ("E", it
->Name());
1285 EXPECT_EQ("/", it
->Path());
1287 ASSERT_TRUE(++it
== cookies
.end());
1289 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1290 it
= cookies
.begin();
1292 ASSERT_TRUE(it
!= cookies
.end());
1293 EXPECT_EQ("C", it
->Name());
1294 EXPECT_EQ("/bar", it
->Path());
1296 ASSERT_TRUE(++it
!= cookies
.end());
1297 EXPECT_EQ("E", it
->Name());
1298 EXPECT_EQ("/", it
->Path());
1300 ASSERT_TRUE(++it
== cookies
.end());
1303 TEST_F(CookieMonsterTest
, DeleteCookieByName
) {
1304 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1306 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A1; path=/"));
1307 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A2; path=/foo"));
1308 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=A3; path=/bar"));
1309 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B1; path=/"));
1310 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B2; path=/foo"));
1311 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=B3; path=/bar"));
1313 DeleteCookie(cm
.get(), GURL(std::string(kUrlGoogle
) + "/foo/bar"), "A");
1315 CookieList cookies
= GetAllCookies(cm
.get());
1316 size_t expected_size
= 4;
1317 EXPECT_EQ(expected_size
, cookies
.size());
1318 for (CookieList::iterator it
= cookies
.begin(); it
!= cookies
.end(); ++it
) {
1319 EXPECT_NE("A1", it
->Value());
1320 EXPECT_NE("A2", it
->Value());
1324 TEST_F(CookieMonsterTest
, ImportCookiesFromCookieMonster
) {
1325 scoped_refptr
<CookieMonster
> cm_1(new CookieMonster(NULL
, NULL
));
1326 CookieOptions options
;
1328 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_foo_
,
1329 "A1=B; path=/foo;", options
));
1330 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_bar_
,
1331 "A2=D; path=/bar;", options
));
1332 EXPECT_TRUE(SetCookieWithOptions(cm_1
.get(), url_google_
, "A3=F;", options
));
1334 CookieList cookies_1
= GetAllCookies(cm_1
.get());
1335 scoped_refptr
<CookieMonster
> cm_2(new CookieMonster(NULL
, NULL
));
1336 ASSERT_TRUE(cm_2
->ImportCookies(cookies_1
));
1337 CookieList cookies_2
= GetAllCookies(cm_2
.get());
1339 size_t expected_size
= 3;
1340 EXPECT_EQ(expected_size
, cookies_2
.size());
1342 CookieList::iterator it
= cookies_2
.begin();
1344 ASSERT_TRUE(it
!= cookies_2
.end());
1345 EXPECT_EQ("A1", it
->Name());
1346 EXPECT_EQ("/foo", it
->Path());
1348 ASSERT_TRUE(++it
!= cookies_2
.end());
1349 EXPECT_EQ("A2", it
->Name());
1350 EXPECT_EQ("/bar", it
->Path());
1352 ASSERT_TRUE(++it
!= cookies_2
.end());
1353 EXPECT_EQ("A3", it
->Name());
1354 EXPECT_EQ("/", it
->Path());
1357 // Tests importing from a persistent cookie store that contains duplicate
1358 // equivalent cookies. This situation should be handled by removing the
1359 // duplicate cookie (both from the in-memory cache, and from the backing store).
1361 // This is a regression test for: http://crbug.com/17855.
1362 TEST_F(CookieMonsterTest
, DontImportDuplicateCookies
) {
1363 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1365 // We will fill some initial cookies into the PersistentCookieStore,
1366 // to simulate a database with 4 duplicates. Note that we need to
1367 // be careful not to have any duplicate creation times at all (as it's a
1368 // violation of a CookieMonster invariant) even if Time::Now() doesn't
1369 // move between calls.
1370 std::vector
<CanonicalCookie
*> initial_cookies
;
1372 // Insert 4 cookies with name "X" on path "/", with varying creation
1373 // dates. We expect only the most recent one to be preserved following
1376 AddCookieToList("www.google.com",
1377 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1378 Time::Now() + TimeDelta::FromDays(3), &initial_cookies
);
1380 AddCookieToList("www.google.com",
1381 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1382 Time::Now() + TimeDelta::FromDays(1), &initial_cookies
);
1384 // ===> This one is the WINNER (biggest creation time). <====
1385 AddCookieToList("www.google.com",
1386 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1387 Time::Now() + TimeDelta::FromDays(4), &initial_cookies
);
1389 AddCookieToList("www.google.com",
1390 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1391 Time::Now(), &initial_cookies
);
1393 // Insert 2 cookies with name "X" on path "/2", with varying creation
1394 // dates. We expect only the most recent one to be preserved the import.
1396 // ===> This one is the WINNER (biggest creation time). <====
1397 AddCookieToList("www.google.com",
1398 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1399 Time::Now() + TimeDelta::FromDays(9), &initial_cookies
);
1401 AddCookieToList("www.google.com",
1402 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1403 Time::Now() + TimeDelta::FromDays(2), &initial_cookies
);
1405 // Insert 1 cookie with name "Y" on path "/".
1406 AddCookieToList("www.google.com",
1407 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1408 Time::Now() + TimeDelta::FromDays(10), &initial_cookies
);
1410 // Inject our initial cookies into the mock PersistentCookieStore.
1411 store
->SetLoadExpectation(true, initial_cookies
);
1413 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1415 // Verify that duplicates were not imported for path "/".
1416 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1417 EXPECT_EQ("X=3; Y=a", GetCookies(cm
.get(), GURL("http://www.google.com/")));
1419 // Verify that same-named cookie on a different path ("/x2") didn't get
1421 EXPECT_EQ("X=a1; X=3; Y=a",
1422 GetCookies(cm
.get(), GURL("http://www.google.com/2/x")));
1424 // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1425 ASSERT_EQ(4u, store
->commands().size());
1426 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[0].type
);
1427 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1428 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[2].type
);
1429 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
1432 // Tests importing from a persistent cookie store that contains cookies
1433 // with duplicate creation times. This situation should be handled by
1434 // dropping the cookies before insertion/visibility to user.
1436 // This is a regression test for: http://crbug.com/43188.
1437 TEST_F(CookieMonsterTest
, DontImportDuplicateCreationTimes
) {
1438 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1440 Time
now(Time::Now());
1441 Time
earlier(now
- TimeDelta::FromDays(1));
1443 // Insert 8 cookies, four with the current time as creation times, and
1444 // four with the earlier time as creation times. We should only get
1445 // two cookies remaining, but which two (other than that there should
1446 // be one from each set) will be random.
1447 std::vector
<CanonicalCookie
*> initial_cookies
;
1448 AddCookieToList("www.google.com", "X=1; path=/", now
, &initial_cookies
);
1449 AddCookieToList("www.google.com", "X=2; path=/", now
, &initial_cookies
);
1450 AddCookieToList("www.google.com", "X=3; path=/", now
, &initial_cookies
);
1451 AddCookieToList("www.google.com", "X=4; path=/", now
, &initial_cookies
);
1453 AddCookieToList("www.google.com", "Y=1; path=/", earlier
, &initial_cookies
);
1454 AddCookieToList("www.google.com", "Y=2; path=/", earlier
, &initial_cookies
);
1455 AddCookieToList("www.google.com", "Y=3; path=/", earlier
, &initial_cookies
);
1456 AddCookieToList("www.google.com", "Y=4; path=/", earlier
, &initial_cookies
);
1458 // Inject our initial cookies into the mock PersistentCookieStore.
1459 store
->SetLoadExpectation(true, initial_cookies
);
1461 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
1463 CookieList
list(GetAllCookies(cm
.get()));
1464 EXPECT_EQ(2U, list
.size());
1465 // Confirm that we have one of each.
1466 std::string
name1(list
[0].Name());
1467 std::string
name2(list
[1].Name());
1468 EXPECT_TRUE(name1
== "X" || name2
== "X");
1469 EXPECT_TRUE(name1
== "Y" || name2
== "Y");
1470 EXPECT_NE(name1
, name2
);
1473 TEST_F(CookieMonsterTest
, CookieMonsterDelegate
) {
1474 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
1475 scoped_refptr
<MockCookieMonsterDelegate
> delegate(
1476 new MockCookieMonsterDelegate
);
1477 scoped_refptr
<CookieMonster
> cm(
1478 new CookieMonster(store
.get(), delegate
.get()));
1480 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
1481 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "C=D"));
1482 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "E=F"));
1483 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm
.get(), url_google_
));
1484 ASSERT_EQ(3u, delegate
->changes().size());
1485 EXPECT_FALSE(delegate
->changes()[0].second
);
1486 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1487 EXPECT_EQ("A", delegate
->changes()[0].first
.Name());
1488 EXPECT_EQ("B", delegate
->changes()[0].first
.Value());
1489 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1490 EXPECT_FALSE(delegate
->changes()[1].second
);
1491 EXPECT_EQ("C", delegate
->changes()[1].first
.Name());
1492 EXPECT_EQ("D", delegate
->changes()[1].first
.Value());
1493 EXPECT_EQ(url_google_
.host(), delegate
->changes()[2].first
.Domain());
1494 EXPECT_FALSE(delegate
->changes()[2].second
);
1495 EXPECT_EQ("E", delegate
->changes()[2].first
.Name());
1496 EXPECT_EQ("F", delegate
->changes()[2].first
.Value());
1499 EXPECT_TRUE(FindAndDeleteCookie(cm
.get(), url_google_
.host(), "C"));
1500 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1501 ASSERT_EQ(1u, delegate
->changes().size());
1502 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1503 EXPECT_TRUE(delegate
->changes()[0].second
);
1504 EXPECT_EQ("C", delegate
->changes()[0].first
.Name());
1505 EXPECT_EQ("D", delegate
->changes()[0].first
.Value());
1508 EXPECT_FALSE(FindAndDeleteCookie(cm
.get(), "random.host", "E"));
1509 EXPECT_EQ("A=B; E=F", GetCookies(cm
.get(), url_google_
));
1510 EXPECT_EQ(0u, delegate
->changes().size());
1512 // Insert a cookie "a" for path "/path1"
1513 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
1514 "a=val1; path=/path1; "
1515 "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1516 ASSERT_EQ(1u, store
->commands().size());
1517 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
1518 ASSERT_EQ(1u, delegate
->changes().size());
1519 EXPECT_FALSE(delegate
->changes()[0].second
);
1520 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1521 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1522 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1525 // Insert a cookie "a" for path "/path1", that is httponly. This should
1526 // overwrite the non-http-only version.
1527 CookieOptions allow_httponly
;
1528 allow_httponly
.set_include_httponly();
1529 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
,
1530 "a=val2; path=/path1; httponly; "
1531 "expires=Mon, 18-Apr-22 22:50:14 GMT",
1533 ASSERT_EQ(3u, store
->commands().size());
1534 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
1535 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
1536 ASSERT_EQ(2u, delegate
->changes().size());
1537 EXPECT_EQ(url_google_
.host(), delegate
->changes()[0].first
.Domain());
1538 EXPECT_TRUE(delegate
->changes()[0].second
);
1539 EXPECT_EQ("a", delegate
->changes()[0].first
.Name());
1540 EXPECT_EQ("val1", delegate
->changes()[0].first
.Value());
1541 EXPECT_EQ(url_google_
.host(), delegate
->changes()[1].first
.Domain());
1542 EXPECT_FALSE(delegate
->changes()[1].second
);
1543 EXPECT_EQ("a", delegate
->changes()[1].first
.Name());
1544 EXPECT_EQ("val2", delegate
->changes()[1].first
.Value());
1548 TEST_F(CookieMonsterTest
, SetCookieWithDetails
) {
1549 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1551 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A", "B",
1552 std::string(), "/foo", base::Time(), false,
1553 false, false, COOKIE_PRIORITY_DEFAULT
));
1554 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_bar_
, "C", "D",
1555 "google.izzle", "/bar", base::Time(), false,
1556 true, false, COOKIE_PRIORITY_DEFAULT
));
1557 EXPECT_TRUE(SetCookieWithDetails(
1558 cm
.get(), url_google_
, "E", "F", std::string(), std::string(),
1559 base::Time(), true, false, false, COOKIE_PRIORITY_DEFAULT
));
1561 // Test that malformed attributes fail to set the cookie.
1562 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, " A", "B",
1563 std::string(), "/foo", base::Time(), false,
1564 false, false, COOKIE_PRIORITY_DEFAULT
));
1565 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A;", "B",
1566 std::string(), "/foo", base::Time(), false,
1567 false, false, COOKIE_PRIORITY_DEFAULT
));
1568 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A=", "B",
1569 std::string(), "/foo", base::Time(), false,
1570 false, false, COOKIE_PRIORITY_DEFAULT
));
1571 EXPECT_FALSE(SetCookieWithDetails(
1572 cm
.get(), url_google_foo_
, "A", "B", "google.ozzzzzzle", "foo",
1573 base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT
));
1574 EXPECT_FALSE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A=", "B",
1575 std::string(), "foo", base::Time(), false,
1576 false, false, COOKIE_PRIORITY_DEFAULT
));
1578 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_foo_
);
1579 CookieList::iterator it
= cookies
.begin();
1581 ASSERT_TRUE(it
!= cookies
.end());
1582 EXPECT_EQ("A", it
->Name());
1583 EXPECT_EQ("B", it
->Value());
1584 EXPECT_EQ("www.google.izzle", it
->Domain());
1585 EXPECT_EQ("/foo", it
->Path());
1586 EXPECT_FALSE(it
->IsPersistent());
1587 EXPECT_FALSE(it
->IsSecure());
1588 EXPECT_FALSE(it
->IsHttpOnly());
1590 ASSERT_TRUE(++it
== cookies
.end());
1592 cookies
= GetAllCookiesForURL(cm
.get(), url_google_bar_
);
1593 it
= cookies
.begin();
1595 ASSERT_TRUE(it
!= cookies
.end());
1596 EXPECT_EQ("C", it
->Name());
1597 EXPECT_EQ("D", it
->Value());
1598 EXPECT_EQ(".google.izzle", it
->Domain());
1599 EXPECT_EQ("/bar", it
->Path());
1600 EXPECT_FALSE(it
->IsSecure());
1601 EXPECT_TRUE(it
->IsHttpOnly());
1603 ASSERT_TRUE(++it
== cookies
.end());
1605 cookies
= GetAllCookiesForURL(cm
.get(), url_google_secure_
);
1606 it
= cookies
.begin();
1608 ASSERT_TRUE(it
!= cookies
.end());
1609 EXPECT_EQ("E", it
->Name());
1610 EXPECT_EQ("F", it
->Value());
1611 EXPECT_EQ("/", it
->Path());
1612 EXPECT_EQ("www.google.izzle", it
->Domain());
1613 EXPECT_TRUE(it
->IsSecure());
1614 EXPECT_FALSE(it
->IsHttpOnly());
1616 ASSERT_TRUE(++it
== cookies
.end());
1619 TEST_F(CookieMonsterTest
, DeleteAllForHost
) {
1620 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1623 // * Non-secure URL, mid-level (http://w.c.b.a)
1624 // * Secure URL, mid-level (https://w.c.b.a)
1625 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1626 // All three tests should nuke only the midlevel host cookie,
1627 // the http_only cookie, the host secure cookie, and the two host
1628 // path cookies. http_only, secure, and paths are ignored by
1629 // this call, and domain cookies arent touched.
1630 PopulateCmForDeleteAllForHost(cm
);
1631 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1632 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1633 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1634 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1635 EXPECT_EQ("dom_1=X; host_1=X",
1636 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1638 "dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1639 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1640 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1641 std::string("/dir1/dir2/xxx"))));
1643 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2
)));
1644 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1646 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1647 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1648 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1649 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1650 EXPECT_EQ("dom_1=X; host_1=X",
1651 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1652 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1653 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1654 std::string("/dir1/dir2/xxx"))));
1656 PopulateCmForDeleteAllForHost(cm
);
1657 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1658 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1660 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1661 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1662 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1663 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1664 EXPECT_EQ("dom_1=X; host_1=X",
1665 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1666 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1667 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1668 std::string("/dir1/dir2/xxx"))));
1670 PopulateCmForDeleteAllForHost(cm
);
1671 EXPECT_EQ(6, DeleteAllForHost(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1672 std::string("/dir1/xxx"))));
1673 EXPECT_EQ(8U, GetAllCookies(cm
.get()).size());
1675 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1676 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus3
)));
1677 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1678 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
)));
1679 EXPECT_EQ("dom_1=X; host_1=X",
1680 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus1
)));
1681 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1682 GetCookies(cm
.get(), GURL(kTopLevelDomainPlus2Secure
+
1683 std::string("/dir1/dir2/xxx"))));
1686 TEST_F(CookieMonsterTest
, UniqueCreationTime
) {
1687 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1688 CookieOptions options
;
1690 // Add in three cookies through every public interface to the
1691 // CookieMonster and confirm that none of them have duplicate
1694 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1695 // are not included as they aren't going to be public for very much
1698 // SetCookie, SetCookieWithOptions, SetCookieWithDetails
1700 SetCookie(cm
.get(), url_google_
, "SetCookie1=A");
1701 SetCookie(cm
.get(), url_google_
, "SetCookie2=A");
1702 SetCookie(cm
.get(), url_google_
, "SetCookie3=A");
1704 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions1=A",
1706 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions2=A",
1708 SetCookieWithOptions(cm
.get(), url_google_
, "setCookieWithOptions3=A",
1711 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails1", "A",
1712 ".google.com", "/", Time(), false, false, false,
1713 COOKIE_PRIORITY_DEFAULT
);
1714 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails2", "A",
1715 ".google.com", "/", Time(), false, false, false,
1716 COOKIE_PRIORITY_DEFAULT
);
1717 SetCookieWithDetails(cm
.get(), url_google_
, "setCookieWithDetails3", "A",
1718 ".google.com", "/", Time(), false, false, false,
1719 COOKIE_PRIORITY_DEFAULT
);
1722 CookieList
cookie_list(GetAllCookies(cm
.get()));
1723 typedef std::map
<int64
, CanonicalCookie
> TimeCookieMap
;
1724 TimeCookieMap check_map
;
1725 for (CookieList::const_iterator it
= cookie_list
.begin();
1726 it
!= cookie_list
.end(); it
++) {
1727 const int64 creation_date
= it
->CreationDate().ToInternalValue();
1728 TimeCookieMap::const_iterator
existing_cookie_it(
1729 check_map
.find(creation_date
));
1730 EXPECT_TRUE(existing_cookie_it
== check_map
.end())
1731 << "Cookie " << it
->Name() << " has same creation date ("
1732 << it
->CreationDate().ToInternalValue()
1733 << ") as previously entered cookie "
1734 << existing_cookie_it
->second
.Name();
1736 if (existing_cookie_it
== check_map
.end()) {
1738 TimeCookieMap::value_type(it
->CreationDate().ToInternalValue(), *it
));
1743 // Mainly a test of GetEffectiveDomain, or more specifically, of the
1744 // expected behavior of GetEffectiveDomain within the CookieMonster.
1745 TEST_F(CookieMonsterTest
, GetKey
) {
1746 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1748 // This test is really only interesting if GetKey() actually does something.
1749 EXPECT_EQ("google.com", cm
->GetKey("www.google.com"));
1750 EXPECT_EQ("google.izzie", cm
->GetKey("www.google.izzie"));
1751 EXPECT_EQ("google.izzie", cm
->GetKey(".google.izzie"));
1752 EXPECT_EQ("bbc.co.uk", cm
->GetKey("bbc.co.uk"));
1753 EXPECT_EQ("bbc.co.uk", cm
->GetKey("a.b.c.d.bbc.co.uk"));
1754 EXPECT_EQ("apple.com", cm
->GetKey("a.b.c.d.apple.com"));
1755 EXPECT_EQ("apple.izzie", cm
->GetKey("a.b.c.d.apple.izzie"));
1757 // Cases where the effective domain is null, so we use the host
1759 EXPECT_EQ("co.uk", cm
->GetKey("co.uk"));
1760 const std::string
extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1761 EXPECT_EQ(extension_name
, cm
->GetKey(extension_name
));
1762 EXPECT_EQ("com", cm
->GetKey("com"));
1763 EXPECT_EQ("hostalias", cm
->GetKey("hostalias"));
1764 EXPECT_EQ("localhost", cm
->GetKey("localhost"));
1767 // Test that cookies transfer from/to the backing store correctly.
1768 TEST_F(CookieMonsterTest
, BackingStoreCommunication
) {
1769 // Store details for cookies transforming through the backing store interface.
1771 base::Time
current(base::Time::Now());
1772 scoped_refptr
<MockSimplePersistentCookieStore
> store(
1773 new MockSimplePersistentCookieStore
);
1774 base::Time new_access_time
;
1775 base::Time
expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1777 const CookiesInputInfo input_info
[] = {
1778 {GURL("http://a.b.google.com"),
1787 COOKIE_PRIORITY_DEFAULT
},
1788 {GURL("https://www.google.com"),
1792 "/path/from/cookie",
1793 expires
+ TimeDelta::FromSeconds(10),
1797 COOKIE_PRIORITY_DEFAULT
},
1798 {GURL("https://google.com"),
1802 "/another/path/to/cookie",
1803 base::Time::Now() + base::TimeDelta::FromSeconds(100),
1807 COOKIE_PRIORITY_DEFAULT
}};
1808 const int INPUT_DELETE
= 1;
1810 // Create new cookies and flush them to the store.
1812 scoped_refptr
<CookieMonster
> cmout(new CookieMonster(store
.get(), NULL
));
1813 for (const CookiesInputInfo
* p
= input_info
;
1814 p
< &input_info
[arraysize(input_info
)]; p
++) {
1815 EXPECT_TRUE(SetCookieWithDetails(cmout
.get(), p
->url
, p
->name
, p
->value
,
1816 p
->domain
, p
->path
, p
->expiration_time
,
1817 p
->secure
, p
->http_only
,
1818 p
->first_party_only
, p
->priority
));
1820 GURL
del_url(input_info
[INPUT_DELETE
]
1821 .url
.Resolve(input_info
[INPUT_DELETE
].path
)
1823 DeleteCookie(cmout
.get(), del_url
, input_info
[INPUT_DELETE
].name
);
1826 // Create a new cookie monster and make sure that everything is correct
1828 scoped_refptr
<CookieMonster
> cmin(new CookieMonster(store
.get(), NULL
));
1829 CookieList
cookies(GetAllCookies(cmin
.get()));
1830 ASSERT_EQ(2u, cookies
.size());
1831 // Ordering is path length, then creation time. So second cookie
1832 // will come first, and we need to swap them.
1833 std::swap(cookies
[0], cookies
[1]);
1834 for (int output_index
= 0; output_index
< 2; output_index
++) {
1835 int input_index
= output_index
* 2;
1836 const CookiesInputInfo
* input
= &input_info
[input_index
];
1837 const CanonicalCookie
* output
= &cookies
[output_index
];
1839 EXPECT_EQ(input
->name
, output
->Name());
1840 EXPECT_EQ(input
->value
, output
->Value());
1841 EXPECT_EQ(input
->url
.host(), output
->Domain());
1842 EXPECT_EQ(input
->path
, output
->Path());
1843 EXPECT_LE(current
.ToInternalValue(),
1844 output
->CreationDate().ToInternalValue());
1845 EXPECT_EQ(input
->secure
, output
->IsSecure());
1846 EXPECT_EQ(input
->http_only
, output
->IsHttpOnly());
1847 EXPECT_EQ(input
->first_party_only
, output
->IsFirstPartyOnly());
1848 EXPECT_TRUE(output
->IsPersistent());
1849 EXPECT_EQ(input
->expiration_time
.ToInternalValue(),
1850 output
->ExpiryDate().ToInternalValue());
1855 TEST_F(CookieMonsterTest
, CookieListOrdering
) {
1856 // Put a random set of cookies into a monster and make sure
1857 // they're returned in the right order.
1858 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1860 SetCookie(cm
.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1"));
1861 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1862 "d=1; domain=b.a.google.com"));
1863 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1864 "a=4; domain=b.a.google.com"));
1865 EXPECT_TRUE(SetCookie(cm
.get(),
1866 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
1867 "e=1; domain=c.b.a.google.com"));
1868 EXPECT_TRUE(SetCookie(cm
.get(),
1869 GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1"));
1870 EXPECT_TRUE(SetCookie(cm
.get(), GURL("http://news.bbc.co.uk/midpath/x.html"),
1874 CookieList
cookies(GetAllCookiesForURL(
1875 cm
.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
1876 ASSERT_EQ(5u, cookies
.size());
1877 EXPECT_EQ("d", cookies
[i
++].Name());
1878 EXPECT_EQ("a", cookies
[i
++].Name());
1879 EXPECT_EQ("e", cookies
[i
++].Name());
1880 EXPECT_EQ("b", cookies
[i
++].Name());
1881 EXPECT_EQ("c", cookies
[i
++].Name());
1886 CookieList
cookies(GetAllCookies(cm
.get()));
1887 ASSERT_EQ(6u, cookies
.size());
1888 EXPECT_EQ("d", cookies
[i
++].Name());
1889 EXPECT_EQ("a", cookies
[i
++].Name());
1890 EXPECT_EQ("e", cookies
[i
++].Name());
1891 EXPECT_EQ("g", cookies
[i
++].Name());
1892 EXPECT_EQ("b", cookies
[i
++].Name());
1893 EXPECT_EQ("c", cookies
[i
++].Name());
1897 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
1898 // are somewhat complementary twins. This test is probing for whether
1899 // garbage collection always happens when it should (i.e. that we actually
1900 // get rid of cookies when we should). The perftest is probing for
1901 // whether garbage collection happens when it shouldn't. See comments
1902 // before that test for more details.
1904 // Disabled on Windows, see crbug.com/126095
1906 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers
1908 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers
1911 TEST_F(CookieMonsterTest
, MAYBE_GarbageCollectionTriggers
) {
1912 // First we check to make sure that a whole lot of recent cookies
1913 // doesn't get rid of anything after garbage collection is checked for.
1915 scoped_refptr
<CookieMonster
> cm(
1916 CreateMonsterForGC(CookieMonster::kMaxCookies
* 2));
1917 EXPECT_EQ(CookieMonster::kMaxCookies
* 2, GetAllCookies(cm
.get()).size());
1918 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
1919 EXPECT_EQ(CookieMonster::kMaxCookies
* 2 + 1,
1920 GetAllCookies(cm
.get()).size());
1923 // Now we explore a series of relationships between cookie last access
1924 // time and size of store to make sure we only get rid of cookies when
1925 // we really should.
1926 const struct TestCase
{
1928 size_t num_old_cookies
;
1929 size_t expected_initial_cookies
;
1930 // Indexed by ExpiryAndKeyScheme
1931 size_t expected_cookies_after_set
;
1933 {// A whole lot of recent cookies; gc shouldn't happen.
1934 CookieMonster::kMaxCookies
* 2,
1936 CookieMonster::kMaxCookies
* 2,
1937 CookieMonster::kMaxCookies
* 2 + 1},
1938 {// Some old cookies, but still overflowing max.
1939 CookieMonster::kMaxCookies
* 2,
1940 CookieMonster::kMaxCookies
/ 2,
1941 CookieMonster::kMaxCookies
* 2,
1942 CookieMonster::kMaxCookies
* 2 - CookieMonster::kMaxCookies
/ 2 + 1},
1943 {// Old cookies enough to bring us right down to our purge line.
1944 CookieMonster::kMaxCookies
* 2,
1945 CookieMonster::kMaxCookies
+ CookieMonster::kPurgeCookies
+ 1,
1946 CookieMonster::kMaxCookies
* 2,
1947 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
},
1948 {// Old cookies enough to bring below our purge line (which we
1950 CookieMonster::kMaxCookies
* 2,
1951 CookieMonster::kMaxCookies
* 3 / 2,
1952 CookieMonster::kMaxCookies
* 2,
1953 CookieMonster::kMaxCookies
- CookieMonster::kPurgeCookies
}};
1955 for (int ci
= 0; ci
< static_cast<int>(arraysize(test_cases
)); ++ci
) {
1956 const TestCase
* test_case
= &test_cases
[ci
];
1957 scoped_refptr
<CookieMonster
> cm(CreateMonsterFromStoreForGC(
1958 test_case
->num_cookies
, test_case
->num_old_cookies
,
1959 CookieMonster::kSafeFromGlobalPurgeDays
* 2));
1960 EXPECT_EQ(test_case
->expected_initial_cookies
,
1961 GetAllCookies(cm
.get()).size())
1962 << "For test case " << ci
;
1964 SetCookie(cm
.get(), GURL("http://newdomain.com"), "b=2");
1965 EXPECT_EQ(test_case
->expected_cookies_after_set
,
1966 GetAllCookies(cm
.get()).size())
1967 << "For test case " << ci
;
1971 // This test checks that keep expired cookies flag is working.
1972 TEST_F(CookieMonsterTest
, KeepExpiredCookies
) {
1973 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
1974 cm
->SetKeepExpiredCookies();
1975 CookieOptions options
;
1977 // Set a persistent cookie.
1978 ASSERT_TRUE(SetCookieWithOptions(
1979 cm
.get(), url_google_
,
1980 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
1983 // Get the canonical cookie.
1984 CookieList cookie_list
= GetAllCookies(cm
.get());
1985 ASSERT_EQ(1U, cookie_list
.size());
1987 // Use a past expiry date to delete the cookie.
1988 ASSERT_TRUE(SetCookieWithOptions(
1989 cm
.get(), url_google_
,
1990 std::string(kValidCookieLine
) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
1993 // Check that the cookie with the past expiry date is still there.
1994 // GetAllCookies() also triggers garbage collection.
1995 cookie_list
= GetAllCookies(cm
.get());
1996 ASSERT_EQ(1U, cookie_list
.size());
1997 ASSERT_TRUE(cookie_list
[0].IsExpired(Time::Now()));
2002 // Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2003 class FlushablePersistentStore
: public CookieMonster::PersistentCookieStore
{
2005 FlushablePersistentStore() : flush_count_(0) {}
2007 void Load(const LoadedCallback
& loaded_callback
) override
{
2008 std::vector
<CanonicalCookie
*> out_cookies
;
2009 base::MessageLoop::current()->PostTask(
2011 base::Bind(&net::LoadedCallbackTask::Run
,
2012 new net::LoadedCallbackTask(loaded_callback
, out_cookies
)));
2015 void LoadCookiesForKey(const std::string
& key
,
2016 const LoadedCallback
& loaded_callback
) override
{
2017 Load(loaded_callback
);
2020 void AddCookie(const CanonicalCookie
&) override
{}
2021 void UpdateCookieAccessTime(const CanonicalCookie
&) override
{}
2022 void DeleteCookie(const CanonicalCookie
&) override
{}
2023 void SetForceKeepSessionState() override
{}
2025 void Flush(const base::Closure
& callback
) override
{
2027 if (!callback
.is_null())
2031 int flush_count() { return flush_count_
; }
2034 ~FlushablePersistentStore() override
{}
2036 volatile int flush_count_
;
2039 // Counts the number of times Callback() has been run.
2040 class CallbackCounter
: public base::RefCountedThreadSafe
<CallbackCounter
> {
2042 CallbackCounter() : callback_count_(0) {}
2044 void Callback() { ++callback_count_
; }
2046 int callback_count() { return callback_count_
; }
2049 friend class base::RefCountedThreadSafe
<CallbackCounter
>;
2050 ~CallbackCounter() {}
2052 volatile int callback_count_
;
2057 // Test that FlushStore() is forwarded to the store and callbacks are posted.
2058 TEST_F(CookieMonsterTest
, FlushStore
) {
2059 scoped_refptr
<CallbackCounter
> counter(new CallbackCounter());
2060 scoped_refptr
<FlushablePersistentStore
> store(new FlushablePersistentStore());
2061 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2063 ASSERT_EQ(0, store
->flush_count());
2064 ASSERT_EQ(0, counter
->callback_count());
2066 // Before initialization, FlushStore() should just run the callback.
2067 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2068 base::MessageLoop::current()->RunUntilIdle();
2070 ASSERT_EQ(0, store
->flush_count());
2071 ASSERT_EQ(1, counter
->callback_count());
2073 // NULL callback is safe.
2074 cm
->FlushStore(base::Closure());
2075 base::MessageLoop::current()->RunUntilIdle();
2077 ASSERT_EQ(0, store
->flush_count());
2078 ASSERT_EQ(1, counter
->callback_count());
2080 // After initialization, FlushStore() should delegate to the store.
2081 GetAllCookies(cm
.get()); // Force init.
2082 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2083 base::MessageLoop::current()->RunUntilIdle();
2085 ASSERT_EQ(1, store
->flush_count());
2086 ASSERT_EQ(2, counter
->callback_count());
2088 // NULL callback is still safe.
2089 cm
->FlushStore(base::Closure());
2090 base::MessageLoop::current()->RunUntilIdle();
2092 ASSERT_EQ(2, store
->flush_count());
2093 ASSERT_EQ(2, counter
->callback_count());
2095 // If there's no backing store, FlushStore() is always a safe no-op.
2096 cm
= new CookieMonster(NULL
, NULL
);
2097 GetAllCookies(cm
.get()); // Force init.
2098 cm
->FlushStore(base::Closure());
2099 base::MessageLoop::current()->RunUntilIdle();
2101 ASSERT_EQ(2, counter
->callback_count());
2103 cm
->FlushStore(base::Bind(&CallbackCounter::Callback
, counter
.get()));
2104 base::MessageLoop::current()->RunUntilIdle();
2106 ASSERT_EQ(3, counter
->callback_count());
2109 TEST_F(CookieMonsterTest
, HistogramCheck
) {
2110 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2111 // Should match call in InitializeHistograms, but doesn't really matter
2112 // since the histogram should have been initialized by the CM construction
2114 base::HistogramBase
* expired_histogram
= base::Histogram::FactoryGet(
2115 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2116 base::Histogram::kUmaTargetedHistogramFlag
);
2118 scoped_ptr
<base::HistogramSamples
> samples1(
2119 expired_histogram
->SnapshotSamples());
2120 ASSERT_TRUE(SetCookieWithDetails(
2121 cm
.get(), GURL("http://fake.a.url"), "a", "b", "a.url", "/",
2122 base::Time::Now() + base::TimeDelta::FromMinutes(59), false, false, false,
2123 COOKIE_PRIORITY_DEFAULT
));
2125 scoped_ptr
<base::HistogramSamples
> samples2(
2126 expired_histogram
->SnapshotSamples());
2127 EXPECT_EQ(samples1
->TotalCount() + 1, samples2
->TotalCount());
2129 // kValidCookieLine creates a session cookie.
2130 ASSERT_TRUE(SetCookie(cm
.get(), url_google_
, kValidCookieLine
));
2132 scoped_ptr
<base::HistogramSamples
> samples3(
2133 expired_histogram
->SnapshotSamples());
2134 EXPECT_EQ(samples2
->TotalCount(), samples3
->TotalCount());
2139 class MultiThreadedCookieMonsterTest
: public CookieMonsterTest
{
2141 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {}
2143 // Helper methods for calling the asynchronous CookieMonster methods
2144 // from a different thread.
2146 void GetAllCookiesTask(CookieMonster
* cm
, GetCookieListCallback
* callback
) {
2147 cm
->GetAllCookiesAsync(
2148 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2151 void GetAllCookiesForURLTask(CookieMonster
* cm
,
2153 GetCookieListCallback
* callback
) {
2154 cm
->GetAllCookiesForURLAsync(url
, base::Bind(&GetCookieListCallback::Run
,
2155 base::Unretained(callback
)));
2158 void GetAllCookiesForURLWithOptionsTask(CookieMonster
* cm
,
2160 const CookieOptions
& options
,
2161 GetCookieListCallback
* callback
) {
2162 cm
->GetAllCookiesForURLWithOptionsAsync(
2164 base::Bind(&GetCookieListCallback::Run
, base::Unretained(callback
)));
2167 void SetCookieWithDetailsTask(CookieMonster
* cm
,
2169 ResultSavingCookieCallback
<bool>* callback
) {
2170 // Define the parameters here instead of in the calling fucntion.
2171 // The maximum number of parameters for Bind function is 6.
2172 std::string name
= "A";
2173 std::string value
= "B";
2174 std::string domain
= std::string();
2175 std::string path
= "/foo";
2176 base::Time expiration_time
= base::Time();
2177 bool secure
= false;
2178 bool http_only
= false;
2179 bool first_party_only
= false;
2180 CookiePriority priority
= COOKIE_PRIORITY_DEFAULT
;
2181 cm
->SetCookieWithDetailsAsync(
2182 url
, name
, value
, domain
, path
, expiration_time
, secure
, http_only
,
2183 first_party_only
, priority
,
2184 base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
2185 base::Unretained(callback
)));
2188 void DeleteAllCreatedBetweenTask(CookieMonster
* cm
,
2189 const base::Time
& delete_begin
,
2190 const base::Time
& delete_end
,
2191 ResultSavingCookieCallback
<int>* callback
) {
2192 cm
->DeleteAllCreatedBetweenAsync(
2193 delete_begin
, delete_end
,
2194 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2195 base::Unretained(callback
)));
2198 void DeleteAllForHostTask(CookieMonster
* cm
,
2200 ResultSavingCookieCallback
<int>* callback
) {
2201 cm
->DeleteAllForHostAsync(url
,
2202 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2203 base::Unretained(callback
)));
2206 void DeleteAllCreatedBetweenForHostTask(
2208 const base::Time delete_begin
,
2209 const base::Time delete_end
,
2211 ResultSavingCookieCallback
<int>* callback
) {
2212 cm
->DeleteAllCreatedBetweenForHostAsync(
2213 delete_begin
, delete_end
, url
,
2214 base::Bind(&ResultSavingCookieCallback
<int>::Run
,
2215 base::Unretained(callback
)));
2218 void DeleteCanonicalCookieTask(CookieMonster
* cm
,
2219 const CanonicalCookie
& cookie
,
2220 ResultSavingCookieCallback
<bool>* callback
) {
2221 cm
->DeleteCanonicalCookieAsync(
2222 cookie
, base::Bind(&ResultSavingCookieCallback
<bool>::Run
,
2223 base::Unretained(callback
)));
2227 void RunOnOtherThread(const base::Closure
& task
) {
2228 other_thread_
.Start();
2229 other_thread_
.message_loop()->PostTask(FROM_HERE
, task
);
2231 other_thread_
.Stop();
2234 Thread other_thread_
;
2239 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookies
) {
2240 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2241 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2242 CookieList cookies
= GetAllCookies(cm
.get());
2243 CookieList::const_iterator it
= cookies
.begin();
2244 ASSERT_TRUE(it
!= cookies
.end());
2245 EXPECT_EQ("www.google.izzle", it
->Domain());
2246 EXPECT_EQ("A", it
->Name());
2247 ASSERT_TRUE(++it
== cookies
.end());
2248 GetCookieListCallback
callback(&other_thread_
);
2249 base::Closure task
=
2250 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesTask
,
2251 base::Unretained(this), cm
, &callback
);
2252 RunOnOtherThread(task
);
2253 EXPECT_TRUE(callback
.did_run());
2254 it
= callback
.cookies().begin();
2255 ASSERT_TRUE(it
!= callback
.cookies().end());
2256 EXPECT_EQ("www.google.izzle", it
->Domain());
2257 EXPECT_EQ("A", it
->Name());
2258 ASSERT_TRUE(++it
== callback
.cookies().end());
2261 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURL
) {
2262 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2263 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2264 CookieList cookies
= GetAllCookiesForURL(cm
.get(), url_google_
);
2265 CookieList::const_iterator it
= cookies
.begin();
2266 ASSERT_TRUE(it
!= cookies
.end());
2267 EXPECT_EQ("www.google.izzle", it
->Domain());
2268 EXPECT_EQ("A", it
->Name());
2269 ASSERT_TRUE(++it
== cookies
.end());
2270 GetCookieListCallback
callback(&other_thread_
);
2271 base::Closure task
=
2272 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask
,
2273 base::Unretained(this), cm
, url_google_
, &callback
);
2274 RunOnOtherThread(task
);
2275 EXPECT_TRUE(callback
.did_run());
2276 it
= callback
.cookies().begin();
2277 ASSERT_TRUE(it
!= callback
.cookies().end());
2278 EXPECT_EQ("www.google.izzle", it
->Domain());
2279 EXPECT_EQ("A", it
->Name());
2280 ASSERT_TRUE(++it
== callback
.cookies().end());
2283 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckGetAllCookiesForURLWithOpt
) {
2284 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2285 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2286 CookieOptions options
;
2287 CookieList cookies
=
2288 GetAllCookiesForURLWithOptions(cm
.get(), url_google_
, options
);
2289 CookieList::const_iterator it
= cookies
.begin();
2290 ASSERT_TRUE(it
!= cookies
.end());
2291 EXPECT_EQ("www.google.izzle", it
->Domain());
2292 EXPECT_EQ("A", it
->Name());
2293 ASSERT_TRUE(++it
== cookies
.end());
2294 GetCookieListCallback
callback(&other_thread_
);
2295 base::Closure task
= base::Bind(
2296 &net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask
,
2297 base::Unretained(this), cm
, url_google_
, options
, &callback
);
2298 RunOnOtherThread(task
);
2299 EXPECT_TRUE(callback
.did_run());
2300 it
= callback
.cookies().begin();
2301 ASSERT_TRUE(it
!= callback
.cookies().end());
2302 EXPECT_EQ("www.google.izzle", it
->Domain());
2303 EXPECT_EQ("A", it
->Name());
2304 ASSERT_TRUE(++it
== callback
.cookies().end());
2307 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckSetCookieWithDetails
) {
2308 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2309 EXPECT_TRUE(SetCookieWithDetails(cm
.get(), url_google_foo_
, "A", "B",
2310 std::string(), "/foo", base::Time(), false,
2311 false, false, COOKIE_PRIORITY_DEFAULT
));
2312 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2313 base::Closure task
=
2314 base::Bind(&net::MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask
,
2315 base::Unretained(this), cm
, url_google_foo_
, &callback
);
2316 RunOnOtherThread(task
);
2317 EXPECT_TRUE(callback
.did_run());
2318 EXPECT_TRUE(callback
.result());
2321 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllCreatedBetween
) {
2322 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2323 CookieOptions options
;
2324 Time now
= Time::Now();
2325 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2326 EXPECT_EQ(1, DeleteAllCreatedBetween(cm
.get(), now
- TimeDelta::FromDays(99),
2328 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2329 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2330 base::Closure task
= base::Bind(
2331 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask
,
2332 base::Unretained(this), cm
, now
- TimeDelta::FromDays(99), Time(),
2334 RunOnOtherThread(task
);
2335 EXPECT_TRUE(callback
.did_run());
2336 EXPECT_EQ(1, callback
.result());
2339 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteAllForHost
) {
2340 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2341 CookieOptions options
;
2342 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2343 EXPECT_EQ(1, DeleteAllForHost(cm
.get(), url_google_
));
2344 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2345 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2346 base::Closure task
=
2347 base::Bind(&net::MultiThreadedCookieMonsterTest::DeleteAllForHostTask
,
2348 base::Unretained(this), cm
, url_google_
, &callback
);
2349 RunOnOtherThread(task
);
2350 EXPECT_TRUE(callback
.did_run());
2351 EXPECT_EQ(1, callback
.result());
2354 TEST_F(MultiThreadedCookieMonsterTest
,
2355 ThreadCheckDeleteAllCreatedBetweenForHost
) {
2356 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2357 GURL
url_not_google("http://www.notgoogle.com");
2359 CookieOptions options
;
2360 Time now
= Time::Now();
2361 // ago1 < ago2 < ago3 < now.
2362 Time ago1
= now
- TimeDelta::FromDays(101);
2363 Time ago2
= now
- TimeDelta::FromDays(100);
2364 Time ago3
= now
- TimeDelta::FromDays(99);
2366 // These 3 cookies match the first deletion.
2367 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2368 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "C=D", options
));
2369 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "Y=Z", options
));
2371 // This cookie does not match host.
2372 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_not_google
, "E=F", options
));
2374 // This cookie does not match time range: [ago3, inf], for first deletion, but
2375 // matches for the second deletion.
2376 EXPECT_TRUE(cm
->SetCookieWithCreationTime(url_google_
, "G=H", ago2
));
2378 // 1. First set of deletions.
2380 3, // Deletes A=B, C=D, Y=Z
2381 DeleteAllCreatedBetweenForHost(cm
.get(), ago3
, Time::Max(), url_google_
));
2383 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2384 ResultSavingCookieCallback
<int> callback(&other_thread_
);
2386 // 2. Second set of deletions.
2387 base::Closure task
= base::Bind(
2388 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask
,
2389 base::Unretained(this), cm
, ago1
, Time(), url_google_
, &callback
);
2390 RunOnOtherThread(task
);
2391 EXPECT_TRUE(callback
.did_run());
2392 EXPECT_EQ(2, callback
.result()); // Deletes A=B, G=H.
2395 TEST_F(MultiThreadedCookieMonsterTest
, ThreadCheckDeleteCanonicalCookie
) {
2396 scoped_refptr
<CookieMonster
> cm(new CookieMonster(NULL
, NULL
));
2397 CookieOptions options
;
2398 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2399 CookieList cookies
= GetAllCookies(cm
.get());
2400 CookieList::iterator it
= cookies
.begin();
2401 EXPECT_TRUE(DeleteCanonicalCookie(cm
.get(), *it
));
2403 EXPECT_TRUE(SetCookieWithOptions(cm
.get(), url_google_
, "A=B", options
));
2404 ResultSavingCookieCallback
<bool> callback(&other_thread_
);
2405 cookies
= GetAllCookies(cm
.get());
2406 it
= cookies
.begin();
2407 base::Closure task
= base::Bind(
2408 &net::MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask
,
2409 base::Unretained(this), cm
, *it
, &callback
);
2410 RunOnOtherThread(task
);
2411 EXPECT_TRUE(callback
.did_run());
2412 EXPECT_TRUE(callback
.result());
2415 // Ensure that cookies for http, https, ws, and wss all share the same storage
2416 // and policies when GetAllCookiesForURLAsync is used. This test is part of
2417 // MultiThreadedCookieMonsterTest in order to test and use
2418 // GetAllCookiesForURLAsync, but it does not use any additional threads.
2419 TEST_F(MultiThreadedCookieMonsterTest
, GetAllCookiesForURLEffectiveDomain
) {
2420 std::vector
<CanonicalCookie
*> cookies
;
2421 // This cookie will be freed by the CookieMonster.
2422 cookies
.push_back(CanonicalCookie::Create(url_google_
, kValidCookieLine
,
2423 Time::Now(), CookieOptions()));
2424 CanonicalCookie cookie
= *cookies
[0];
2425 scoped_refptr
<NewMockPersistentCookieStore
> store(
2426 new NewMockPersistentCookieStore
);
2427 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2429 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback
;
2430 ::testing::StrictMock
<::testing::MockFunction
<void(int)>> checkpoint
;
2431 const std::string key
=
2432 cookie_util::GetEffectiveDomain(url_google_
.scheme(), url_google_
.host());
2434 ::testing::InSequence s
;
2435 EXPECT_CALL(checkpoint
, Call(0));
2436 EXPECT_CALL(*store
, Load(::testing::_
));
2437 EXPECT_CALL(*store
, LoadCookiesForKey(key
, ::testing::_
))
2438 .WillOnce(::testing::SaveArg
<1>(&loaded_callback
));
2439 EXPECT_CALL(checkpoint
, Call(1));
2440 // LoadCookiesForKey will never be called after checkpoint.Call(1) although
2441 // we will call GetAllCookiesForURLAsync again, because all URLs below share
2443 EXPECT_CALL(*store
, LoadCookiesForKey(::testing::_
, ::testing::_
)).Times(0);
2445 GetCookieListCallback callback
;
2447 GetAllCookiesForURLTask(cm
.get(), url_google_
, &callback
);
2449 ASSERT_FALSE(callback
.did_run());
2450 // Pass the cookies to the CookieMonster.
2451 loaded_callback
.Run(cookies
);
2452 // Now GetAllCookiesForURLTask is done.
2453 ASSERT_TRUE(callback
.did_run());
2454 // See that the callback was called with the cookies.
2455 ASSERT_EQ(1u, callback
.cookies().size());
2456 EXPECT_TRUE(cookie
.IsEquivalent(callback
.cookies()[0]));
2458 // All urls in |urls| should share the same cookie domain.
2459 const GURL kUrls
[] = {
2462 GURL(kUrlGoogleWebSocket
),
2463 GURL(kUrlGoogleWebSocketSecure
),
2465 for (const GURL
& url
: kUrls
) {
2466 // Call the function with |url| and verify it is done synchronously without
2467 // calling LoadCookiesForKey.
2468 GetCookieListCallback callback
;
2469 GetAllCookiesForURLTask(cm
.get(), url
, &callback
);
2470 ASSERT_TRUE(callback
.did_run());
2471 ASSERT_EQ(1u, callback
.cookies().size());
2472 EXPECT_TRUE(cookie
.IsEquivalent(callback
.cookies()[0]));
2476 TEST_F(CookieMonsterTest
, InvalidExpiryTime
) {
2477 std::string cookie_line
=
2478 std::string(kValidCookieLine
) + "; expires=Blarg arg arg";
2479 scoped_ptr
<CanonicalCookie
> cookie(CanonicalCookie::Create(
2480 url_google_
, cookie_line
, Time::Now(), CookieOptions()));
2481 ASSERT_FALSE(cookie
->IsPersistent());
2484 // Test that CookieMonster writes session cookies into the underlying
2485 // CookieStore if the "persist session cookies" option is on.
2486 TEST_F(CookieMonsterTest
, PersistSessionCookies
) {
2487 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2488 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2489 cm
->SetPersistSessionCookies(true);
2491 // All cookies set with SetCookie are session cookies.
2492 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B"));
2493 EXPECT_EQ("A=B", GetCookies(cm
.get(), url_google_
));
2495 // The cookie was written to the backing store.
2496 EXPECT_EQ(1u, store
->commands().size());
2497 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2498 EXPECT_EQ("A", store
->commands()[0].cookie
.Name());
2499 EXPECT_EQ("B", store
->commands()[0].cookie
.Value());
2501 // Modify the cookie.
2502 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=C"));
2503 EXPECT_EQ("A=C", GetCookies(cm
.get(), url_google_
));
2504 EXPECT_EQ(3u, store
->commands().size());
2505 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2506 EXPECT_EQ("A", store
->commands()[1].cookie
.Name());
2507 EXPECT_EQ("B", store
->commands()[1].cookie
.Value());
2508 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2509 EXPECT_EQ("A", store
->commands()[2].cookie
.Name());
2510 EXPECT_EQ("C", store
->commands()[2].cookie
.Value());
2512 // Delete the cookie.
2513 DeleteCookie(cm
.get(), url_google_
, "A");
2514 EXPECT_EQ("", GetCookies(cm
.get(), url_google_
));
2515 EXPECT_EQ(4u, store
->commands().size());
2516 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2517 EXPECT_EQ("A", store
->commands()[3].cookie
.Name());
2518 EXPECT_EQ("C", store
->commands()[3].cookie
.Value());
2521 // Test the commands sent to the persistent cookie store.
2522 TEST_F(CookieMonsterTest
, PersisentCookieStorageTest
) {
2523 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2524 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2527 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2528 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2529 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2530 ASSERT_EQ(1u, store
->commands().size());
2531 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[0].type
);
2533 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "A=B; max-age=0"));
2534 this->MatchCookieLines(std::string(), GetCookies(cm
.get(), url_google_
));
2535 ASSERT_EQ(2u, store
->commands().size());
2536 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[1].type
);
2539 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2540 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2541 this->MatchCookieLines("A=B", GetCookies(cm
.get(), url_google_
));
2542 ASSERT_EQ(3u, store
->commands().size());
2543 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[2].type
);
2545 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
,
2546 "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
2547 this->MatchCookieLines("A=Foo", GetCookies(cm
.get(), url_google_
));
2548 ASSERT_EQ(5u, store
->commands().size());
2549 EXPECT_EQ(CookieStoreCommand::REMOVE
, store
->commands()[3].type
);
2550 EXPECT_EQ(CookieStoreCommand::ADD
, store
->commands()[4].type
);
2552 // Create some non-persistent cookies and check that they don't go to the
2553 // persistent storage.
2554 EXPECT_TRUE(SetCookie(cm
.get(), url_google_
, "B=Bar"));
2555 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm
.get(), url_google_
));
2556 EXPECT_EQ(5u, store
->commands().size());
2559 // Test to assure that cookies with control characters are purged appropriately.
2560 // See http://crbug.com/238041 for background.
2561 TEST_F(CookieMonsterTest
, ControlCharacterPurge
) {
2562 const Time
now1(Time::Now());
2563 const Time
now2(Time::Now() + TimeDelta::FromSeconds(1));
2564 const Time
now3(Time::Now() + TimeDelta::FromSeconds(2));
2565 const Time
later(now1
+ TimeDelta::FromDays(1));
2566 const GURL
url("http://host/path");
2567 const std::string
domain("host");
2568 const std::string
path("/path");
2570 scoped_refptr
<MockPersistentCookieStore
> store(new MockPersistentCookieStore
);
2572 std::vector
<CanonicalCookie
*> initial_cookies
;
2574 AddCookieToList(domain
, "foo=bar; path=" + path
, now1
, &initial_cookies
);
2576 // We have to manually build this cookie because it contains a control
2577 // character, and our cookie line parser rejects control characters.
2578 CanonicalCookie
* cc
=
2579 new CanonicalCookie(url
, "baz",
2582 domain
, path
, now2
, later
, now2
, false, false, false,
2583 COOKIE_PRIORITY_DEFAULT
);
2584 initial_cookies
.push_back(cc
);
2586 AddCookieToList(domain
, "hello=world; path=" + path
, now3
, &initial_cookies
);
2588 // Inject our initial cookies into the mock PersistentCookieStore.
2589 store
->SetLoadExpectation(true, initial_cookies
);
2591 scoped_refptr
<CookieMonster
> cm(new CookieMonster(store
.get(), NULL
));
2593 EXPECT_EQ("foo=bar; hello=world", GetCookies(cm
.get(), url
));
2596 class CookieMonsterNotificationTest
: public CookieMonsterTest
{
2598 CookieMonsterNotificationTest()
2599 : test_url_("http://www.google.com/foo"),
2600 store_(new MockPersistentCookieStore
),
2601 monster_(new CookieMonster(store_
.get(), NULL
)) {}
2603 ~CookieMonsterNotificationTest() override
{}
2605 CookieMonster
* monster() { return monster_
.get(); }
2608 const GURL test_url_
;
2611 scoped_refptr
<MockPersistentCookieStore
> store_
;
2612 scoped_refptr
<CookieMonster
> monster_
;
2615 void RecordCookieChanges(std::vector
<net::CanonicalCookie
>* out_cookies
,
2616 std::vector
<bool>* out_removes
,
2617 const net::CanonicalCookie
& cookie
,
2619 DCHECK(out_cookies
);
2620 out_cookies
->push_back(cookie
);
2622 out_removes
->push_back(removed
);
2625 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithNoCookie
) {
2626 std::vector
<net::CanonicalCookie
> cookies
;
2627 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2628 monster()->AddCallbackForCookie(
2630 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2631 base::MessageLoop::current()->RunUntilIdle();
2632 EXPECT_EQ(0U, cookies
.size());
2635 TEST_F(CookieMonsterNotificationTest
, NoNotifyWithInitialCookie
) {
2636 std::vector
<net::CanonicalCookie
> cookies
;
2637 SetCookie(monster(), test_url_
, "abc=def");
2638 base::MessageLoop::current()->RunUntilIdle();
2639 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2640 monster()->AddCallbackForCookie(
2642 base::Bind(&RecordCookieChanges
, &cookies
, nullptr)));
2643 base::MessageLoop::current()->RunUntilIdle();
2644 EXPECT_EQ(0U, cookies
.size());
2647 TEST_F(CookieMonsterNotificationTest
, NotifyOnSet
) {
2648 std::vector
<net::CanonicalCookie
> cookies
;
2649 std::vector
<bool> removes
;
2650 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2651 monster()->AddCallbackForCookie(
2653 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2654 SetCookie(monster(), test_url_
, "abc=def");
2655 base::MessageLoop::current()->RunUntilIdle();
2656 EXPECT_EQ(1U, cookies
.size());
2657 EXPECT_EQ(1U, removes
.size());
2659 EXPECT_EQ("abc", cookies
[0].Name());
2660 EXPECT_EQ("def", cookies
[0].Value());
2661 EXPECT_FALSE(removes
[0]);
2664 TEST_F(CookieMonsterNotificationTest
, NotifyOnDelete
) {
2665 std::vector
<net::CanonicalCookie
> cookies
;
2666 std::vector
<bool> removes
;
2667 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2668 monster()->AddCallbackForCookie(
2670 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2671 SetCookie(monster(), test_url_
, "abc=def");
2672 base::MessageLoop::current()->RunUntilIdle();
2673 EXPECT_EQ(1U, cookies
.size());
2674 EXPECT_EQ(1U, removes
.size());
2676 DeleteCookie(monster(), test_url_
, "abc");
2677 base::MessageLoop::current()->RunUntilIdle();
2678 EXPECT_EQ(2U, cookies
.size());
2679 EXPECT_EQ(2U, removes
.size());
2681 EXPECT_EQ("abc", cookies
[1].Name());
2682 EXPECT_EQ("def", cookies
[1].Value());
2683 EXPECT_TRUE(removes
[1]);
2686 TEST_F(CookieMonsterNotificationTest
, NotifyOnUpdate
) {
2687 std::vector
<net::CanonicalCookie
> cookies
;
2688 std::vector
<bool> removes
;
2689 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub(
2690 monster()->AddCallbackForCookie(
2692 base::Bind(&RecordCookieChanges
, &cookies
, &removes
)));
2693 SetCookie(monster(), test_url_
, "abc=def");
2694 base::MessageLoop::current()->RunUntilIdle();
2695 EXPECT_EQ(1U, cookies
.size());
2697 // Replacing an existing cookie is actually a two-phase delete + set
2698 // operation, so we get an extra notification.
2699 SetCookie(monster(), test_url_
, "abc=ghi");
2700 base::MessageLoop::current()->RunUntilIdle();
2702 EXPECT_EQ(3U, cookies
.size());
2703 EXPECT_EQ(3U, removes
.size());
2705 EXPECT_EQ("abc", cookies
[1].Name());
2706 EXPECT_EQ("def", cookies
[1].Value());
2707 EXPECT_TRUE(removes
[1]);
2709 EXPECT_EQ("abc", cookies
[2].Name());
2710 EXPECT_EQ("ghi", cookies
[2].Value());
2711 EXPECT_FALSE(removes
[2]);
2714 TEST_F(CookieMonsterNotificationTest
, MultipleNotifies
) {
2715 std::vector
<net::CanonicalCookie
> cookies0
;
2716 std::vector
<net::CanonicalCookie
> cookies1
;
2717 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
2718 monster()->AddCallbackForCookie(
2720 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
2721 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
2722 monster()->AddCallbackForCookie(
2724 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
2725 SetCookie(monster(), test_url_
, "abc=def");
2726 base::MessageLoop::current()->RunUntilIdle();
2727 EXPECT_EQ(1U, cookies0
.size());
2728 EXPECT_EQ(0U, cookies1
.size());
2729 SetCookie(monster(), test_url_
, "def=abc");
2730 base::MessageLoop::current()->RunUntilIdle();
2731 EXPECT_EQ(1U, cookies0
.size());
2732 EXPECT_EQ(1U, cookies1
.size());
2735 TEST_F(CookieMonsterNotificationTest
, MultipleSameNotifies
) {
2736 std::vector
<net::CanonicalCookie
> cookies0
;
2737 std::vector
<net::CanonicalCookie
> cookies1
;
2738 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub0(
2739 monster()->AddCallbackForCookie(
2741 base::Bind(&RecordCookieChanges
, &cookies0
, nullptr)));
2742 scoped_ptr
<CookieStore::CookieChangedSubscription
> sub1(
2743 monster()->AddCallbackForCookie(
2745 base::Bind(&RecordCookieChanges
, &cookies1
, nullptr)));
2746 SetCookie(monster(), test_url_
, "abc=def");
2747 base::MessageLoop::current()->RunUntilIdle();
2748 EXPECT_EQ(1U, cookies0
.size());
2749 EXPECT_EQ(1U, cookies0
.size());