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