Record error when CreateDir fails.
[chromium-blink-merge.git] / net / cookies / cookie_monster_unittest.cc
blobf6e0ae388fa41f59db96681e6c840a2c7074c966
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.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.h"
25 #include "googleurl/src/gurl.h"
26 #include "net/cookies/canonical_cookie.h"
27 #include "net/cookies/cookie_constants.h"
28 #include "net/cookies/cookie_monster.h"
29 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
30 #include "net/cookies/cookie_util.h"
31 #include "net/cookies/parsed_cookie.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
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 MOCK_METHOD1(Flush, void(const base::Closure& callback));
54 MOCK_METHOD0(SetForceKeepSessionState, void());
56 private:
57 virtual ~NewMockPersistentCookieStore() {}
60 const char* kTopLevelDomainPlus1 = "http://www.harvard.edu";
61 const char* kTopLevelDomainPlus2 = "http://www.math.harvard.edu";
62 const char* kTopLevelDomainPlus2Secure = "https://www.math.harvard.edu";
63 const char* kTopLevelDomainPlus3 =
64 "http://www.bourbaki.math.harvard.edu";
65 const char* kOtherDomain = "http://www.mit.edu";
66 const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle";
68 class GetCookieListCallback : public CookieCallback {
69 public:
70 GetCookieListCallback() {}
71 explicit GetCookieListCallback(Thread* run_in_thread)
72 : CookieCallback(run_in_thread) {}
74 void Run(const CookieList& cookies) {
75 cookies_ = cookies;
76 CallbackEpilogue();
79 const CookieList& cookies() { return cookies_; }
81 private:
82 CookieList cookies_;
85 struct CookieMonsterTestTraits {
86 static scoped_refptr<CookieStore> Create() {
87 return new CookieMonster(NULL, NULL);
90 static const bool is_cookie_monster = true;
91 static const bool supports_http_only = true;
92 static const bool supports_cookies_with_info = true;
93 static const bool supports_non_dotted_domains = true;
94 static const bool supports_trailing_dots = true;
95 static const bool filters_schemes = true;
96 static const bool has_path_prefix_bug = false;
97 static const int creation_time_granularity_in_ms = 0;
100 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster,
101 CookieStoreTest,
102 CookieMonsterTestTraits);
104 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster,
105 MultiThreadedCookieStoreTest,
106 CookieMonsterTestTraits);
108 class CookieMonsterTest : public CookieStoreTest<CookieMonsterTestTraits> {
109 protected:
111 CookieList GetAllCookies(CookieMonster* cm) {
112 DCHECK(cm);
113 GetCookieListCallback callback;
114 cm->GetAllCookiesAsync(
115 base::Bind(&GetCookieListCallback::Run,
116 base::Unretained(&callback)));
117 RunFor(kTimeout);
118 EXPECT_TRUE(callback.did_run());
119 return callback.cookies();
122 CookieList GetAllCookiesForURL(CookieMonster* cm,
123 const GURL& url) {
124 DCHECK(cm);
125 GetCookieListCallback callback;
126 cm->GetAllCookiesForURLAsync(
127 url, base::Bind(&GetCookieListCallback::Run,
128 base::Unretained(&callback)));
129 RunFor(kTimeout);
130 EXPECT_TRUE(callback.did_run());
131 return callback.cookies();
134 CookieList GetAllCookiesForURLWithOptions(CookieMonster* cm,
135 const GURL& url,
136 const CookieOptions& options) {
137 DCHECK(cm);
138 GetCookieListCallback callback;
139 cm->GetAllCookiesForURLWithOptionsAsync(
140 url, options, base::Bind(&GetCookieListCallback::Run,
141 base::Unretained(&callback)));
142 RunFor(kTimeout);
143 EXPECT_TRUE(callback.did_run());
144 return callback.cookies();
147 bool SetCookieWithDetails(CookieMonster* cm,
148 const GURL& url,
149 const std::string& name,
150 const std::string& value,
151 const std::string& domain,
152 const std::string& path,
153 const base::Time& expiration_time,
154 bool secure,
155 bool http_only,
156 CookiePriority priority) {
157 DCHECK(cm);
158 BoolResultCookieCallback callback;
159 cm->SetCookieWithDetailsAsync(
160 url, name, value, domain, path, expiration_time, secure, http_only,
161 priority,
162 base::Bind(&BoolResultCookieCallback::Run,
163 base::Unretained(&callback)));
164 RunFor(kTimeout);
165 EXPECT_TRUE(callback.did_run());
166 return callback.result();
169 int DeleteAll(CookieMonster*cm) {
170 DCHECK(cm);
171 IntResultCookieCallback callback;
172 cm->DeleteAllAsync(
173 base::Bind(&IntResultCookieCallback::Run, base::Unretained(&callback)));
174 RunFor(kTimeout);
175 EXPECT_TRUE(callback.did_run());
176 return callback.result();
179 int DeleteAllCreatedBetween(CookieMonster*cm,
180 const base::Time& delete_begin,
181 const base::Time& delete_end) {
182 DCHECK(cm);
183 IntResultCookieCallback callback;
184 cm->DeleteAllCreatedBetweenAsync(
185 delete_begin, delete_end,
186 base::Bind(&IntResultCookieCallback::Run, base::Unretained(&callback)));
187 RunFor(kTimeout);
188 EXPECT_TRUE(callback.did_run());
189 return callback.result();
192 int DeleteAllForHost(CookieMonster*cm,
193 const GURL& url) {
194 DCHECK(cm);
195 IntResultCookieCallback callback;
196 cm->DeleteAllForHostAsync(
197 url, base::Bind(&IntResultCookieCallback::Run,
198 base::Unretained(&callback)));
199 RunFor(kTimeout);
200 EXPECT_TRUE(callback.did_run());
201 return callback.result();
204 bool DeleteCanonicalCookie(CookieMonster*cm, const CanonicalCookie& cookie) {
205 DCHECK(cm);
206 BoolResultCookieCallback callback;
207 cm->DeleteCanonicalCookieAsync(
208 cookie,
209 base::Bind(&BoolResultCookieCallback::Run,
210 base::Unretained(&callback)));
211 RunFor(kTimeout);
212 EXPECT_TRUE(callback.did_run());
213 return callback.result();
216 // Helper for DeleteAllForHost test; repopulates CM with same layout
217 // each time.
218 void PopulateCmForDeleteAllForHost(scoped_refptr<CookieMonster> cm) {
219 GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1);
220 GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2);
221 GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure);
222 GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3);
223 GURL url_other(kOtherDomain);
225 DeleteAll(cm.get());
227 // Static population for probe:
228 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
229 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
230 // * http_only cookie (w.c.b.a)
231 // * Two secure cookies (.c.b.a, w.c.b.a)
232 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
233 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
235 // Domain cookies
236 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
237 url_top_level_domain_plus_1,
238 "dom_1",
239 "X",
240 ".harvard.edu",
241 "/",
242 base::Time(),
243 false,
244 false,
245 COOKIE_PRIORITY_DEFAULT));
246 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
247 url_top_level_domain_plus_2,
248 "dom_2",
249 "X",
250 ".math.harvard.edu",
251 "/",
252 base::Time(),
253 false,
254 false,
255 COOKIE_PRIORITY_DEFAULT));
256 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
257 url_top_level_domain_plus_3,
258 "dom_3",
259 "X",
260 ".bourbaki.math.harvard.edu",
261 "/",
262 base::Time(),
263 false,
264 false,
265 COOKIE_PRIORITY_DEFAULT));
267 // Host cookies
268 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
269 url_top_level_domain_plus_1,
270 "host_1",
271 "X",
272 std::string(),
273 "/",
274 base::Time(),
275 false,
276 false,
277 COOKIE_PRIORITY_DEFAULT));
278 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
279 url_top_level_domain_plus_2,
280 "host_2",
281 "X",
282 std::string(),
283 "/",
284 base::Time(),
285 false,
286 false,
287 COOKIE_PRIORITY_DEFAULT));
288 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
289 url_top_level_domain_plus_3,
290 "host_3",
291 "X",
292 std::string(),
293 "/",
294 base::Time(),
295 false,
296 false,
297 COOKIE_PRIORITY_DEFAULT));
299 // Http_only cookie
300 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
301 url_top_level_domain_plus_2,
302 "httpo_check",
303 "X",
304 std::string(),
305 "/",
306 base::Time(),
307 false,
308 true,
309 COOKIE_PRIORITY_DEFAULT));
311 // Secure cookies
312 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
313 url_top_level_domain_plus_2_secure,
314 "sec_dom",
315 "X",
316 ".math.harvard.edu",
317 "/",
318 base::Time(),
319 true,
320 false,
321 COOKIE_PRIORITY_DEFAULT));
322 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
323 url_top_level_domain_plus_2_secure,
324 "sec_host",
325 "X",
326 std::string(),
327 "/",
328 base::Time(),
329 true,
330 false,
331 COOKIE_PRIORITY_DEFAULT));
333 // Domain path cookies
334 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
335 url_top_level_domain_plus_2,
336 "dom_path_1",
337 "X",
338 ".math.harvard.edu",
339 "/dir1",
340 base::Time(),
341 false,
342 false,
343 COOKIE_PRIORITY_DEFAULT));
344 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
345 url_top_level_domain_plus_2,
346 "dom_path_2",
347 "X",
348 ".math.harvard.edu",
349 "/dir1/dir2",
350 base::Time(),
351 false,
352 false,
353 COOKIE_PRIORITY_DEFAULT));
355 // Host path cookies
356 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
357 url_top_level_domain_plus_2,
358 "host_path_1",
359 "X",
360 std::string(),
361 "/dir1",
362 base::Time(),
363 false,
364 false,
365 COOKIE_PRIORITY_DEFAULT));
366 EXPECT_TRUE(this->SetCookieWithDetails(cm.get(),
367 url_top_level_domain_plus_2,
368 "host_path_2",
369 "X",
370 std::string(),
371 "/dir1/dir2",
372 base::Time(),
373 false,
374 false,
375 COOKIE_PRIORITY_DEFAULT));
377 EXPECT_EQ(13U, this->GetAllCookies(cm.get()).size());
380 Time GetFirstCookieAccessDate(CookieMonster* cm) {
381 const CookieList all_cookies(this->GetAllCookies(cm));
382 return all_cookies.front().LastAccessDate();
385 bool FindAndDeleteCookie(CookieMonster* cm,
386 const std::string& domain,
387 const std::string& name) {
388 CookieList cookies = this->GetAllCookies(cm);
389 for (CookieList::iterator it = cookies.begin();
390 it != cookies.end(); ++it)
391 if (it->Domain() == domain && it->Name() == name)
392 return this->DeleteCanonicalCookie(cm, *it);
393 return false;
396 int CountInString(const std::string& str, char c) {
397 return std::count(str.begin(), str.end(), c);
400 void TestHostGarbageCollectHelper() {
401 int domain_max_cookies = CookieMonster::kDomainMaxCookies;
402 int domain_purge_cookies = CookieMonster::kDomainPurgeCookies;
403 const int more_than_enough_cookies =
404 (domain_max_cookies + domain_purge_cookies) * 2;
405 // Add a bunch of cookies on a single host, should purge them.
407 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
408 for (int i = 0; i < more_than_enough_cookies; ++i) {
409 std::string cookie = base::StringPrintf("a%03d=b", i);
410 EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie));
411 std::string cookies = this->GetCookies(cm.get(), url_google_);
412 // Make sure we find it in the cookies.
413 EXPECT_NE(cookies.find(cookie), std::string::npos);
414 // Count the number of cookies.
415 EXPECT_LE(CountInString(cookies, '='), domain_max_cookies);
419 // Add a bunch of cookies on multiple hosts within a single eTLD.
420 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
421 // between them. We shouldn't go above kDomainMaxCookies for both together.
422 GURL url_google_specific(kUrlGoogleSpecific);
424 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
425 for (int i = 0; i < more_than_enough_cookies; ++i) {
426 std::string cookie_general = base::StringPrintf("a%03d=b", i);
427 EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie_general));
428 std::string cookie_specific = base::StringPrintf("c%03d=b", i);
429 EXPECT_TRUE(SetCookie(cm.get(), url_google_specific, cookie_specific));
430 std::string cookies_general = this->GetCookies(cm.get(), url_google_);
431 EXPECT_NE(cookies_general.find(cookie_general), std::string::npos);
432 std::string cookies_specific =
433 this->GetCookies(cm.get(), url_google_specific);
434 EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos);
435 EXPECT_LE((CountInString(cookies_general, '=') +
436 CountInString(cookies_specific, '=')),
437 domain_max_cookies);
439 // After all this, there should be at least
440 // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
441 std::string cookies_general = this->GetCookies(cm.get(), url_google_);
442 std::string cookies_specific =
443 this->GetCookies(cm.get(), url_google_specific);
444 int total_cookies = (CountInString(cookies_general, '=') +
445 CountInString(cookies_specific, '='));
446 EXPECT_GE(total_cookies, domain_max_cookies - domain_purge_cookies);
447 EXPECT_LE(total_cookies, domain_max_cookies);
451 CookiePriority CharToPriority(char ch) {
452 switch (ch) {
453 case 'L':
454 return COOKIE_PRIORITY_LOW;
455 case 'M':
456 return COOKIE_PRIORITY_MEDIUM;
457 case 'H':
458 return COOKIE_PRIORITY_HIGH;
460 NOTREACHED();
461 return COOKIE_PRIORITY_DEFAULT;
464 // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
465 // priorities specified by |coded_priority_str|, and tests priority-aware
466 // domain cookie eviction.
467 // |coded_priority_str| specifies a run-length-encoded string of priorities.
468 // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
469 // from least- to most-recently accessed) insertion of 2 medium-priority
470 // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4
471 // high-priority cookies.
472 // Within each priority, only the least-accessed cookies should be evicted.
473 // Thus, to describe expected suriving cookies, it suffices to specify the
474 // expected population of surviving cookies per priority, i.e.,
475 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
476 void TestPriorityCookieCase(CookieMonster* cm,
477 const std::string& coded_priority_str,
478 size_t expected_low_count,
479 size_t expected_medium_count,
480 size_t expected_high_count) {
481 DeleteAll(cm);
482 int next_cookie_id = 0;
483 std::vector<CookiePriority> priority_list;
484 std::vector<int> id_list[3]; // Indexed by CookiePriority.
486 // Parse |coded_priority_str| and add cookies.
487 std::vector<std::string> priority_tok_list;
488 base::SplitString(coded_priority_str, ' ', &priority_tok_list);
489 for (std::vector<std::string>::iterator it = priority_tok_list.begin();
490 it != priority_tok_list.end(); ++it) {
491 size_t len = it->length();
492 DCHECK_NE(len, 0U);
493 // Take last character as priority.
494 CookiePriority priority = CharToPriority((*it)[len - 1]);
495 std::string priority_str = CookiePriorityToString(priority);
496 // The rest of the string (possibly empty) specifies repetition.
497 int rep = 1;
498 if (!it->empty()) {
499 bool result = base::StringToInt(
500 base::StringPiece(it->begin(), it->end() - 1), &rep);
501 DCHECK(result);
503 for (; rep > 0; --rep, ++next_cookie_id) {
504 std::string cookie = base::StringPrintf(
505 "a%d=b;priority=%s", next_cookie_id, priority_str.c_str());
506 EXPECT_TRUE(SetCookie(cm, url_google_, cookie));
507 priority_list.push_back(priority);
508 id_list[priority].push_back(next_cookie_id);
512 int num_cookies = static_cast<int>(priority_list.size());
513 std::vector<int> surviving_id_list[3]; // Indexed by CookiePriority.
515 // Parse the list of cookies
516 std::string cookie_str = this->GetCookies(cm, url_google_);
517 std::vector<std::string> cookie_tok_list;
518 base::SplitString(cookie_str, ';', &cookie_tok_list);
519 for (std::vector<std::string>::iterator it = cookie_tok_list.begin();
520 it != cookie_tok_list.end(); ++it) {
521 // Assuming *it is "a#=b", so extract and parse "#" portion.
522 int id = -1;
523 bool result = base::StringToInt(
524 base::StringPiece(it->begin() + 1, it->end() - 2), &id);
525 DCHECK(result);
526 DCHECK_GE(id, 0);
527 DCHECK_LT(id, num_cookies);
528 surviving_id_list[priority_list[id]].push_back(id);
531 // Validate each priority.
532 size_t expected_count[3] = {
533 expected_low_count, expected_medium_count, expected_high_count
535 for (int i = 0; i < 3; ++i) {
536 DCHECK_LE(surviving_id_list[i].size(), id_list[i].size());
537 EXPECT_EQ(expected_count[i], surviving_id_list[i].size());
538 // Verify that the remaining cookies are the most recent among those
539 // with the same priorities.
540 if (expected_count[i] == surviving_id_list[i].size()) {
541 std::sort(surviving_id_list[i].begin(), surviving_id_list[i].end());
542 EXPECT_TRUE(std::equal(surviving_id_list[i].begin(),
543 surviving_id_list[i].end(),
544 id_list[i].end() - expected_count[i]));
549 void TestPriorityAwareGarbageCollectHelper() {
550 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
551 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies);
552 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
553 CookieMonster::kDomainPurgeCookies);
554 DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow);
555 DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium);
556 DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh);
558 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
559 cm->SetPriorityAwareGarbageCollection(true);
561 // Each test case adds 181 cookies, so 31 cookies are evicted.
562 // Cookie same priority, repeated for each priority.
563 TestPriorityCookieCase(cm.get(), "181L", 150U, 0U, 0U);
564 TestPriorityCookieCase(cm.get(), "181M", 0U, 150U, 0U);
565 TestPriorityCookieCase(cm.get(), "181H", 0U, 0U, 150U);
567 // Pairwise scenarios.
568 // Round 1 => none; round2 => 31M; round 3 => none.
569 TestPriorityCookieCase(cm.get(), "10H 171M", 0U, 140U, 10U);
570 // Round 1 => 10L; round2 => 21M; round 3 => none.
571 TestPriorityCookieCase(cm.get(), "141M 40L", 30U, 120U, 0U);
572 // Round 1 => none; round2 => none; round 3 => 31H.
573 TestPriorityCookieCase(cm.get(), "101H 80M", 0U, 80U, 70U);
575 // For {low, medium} priorities right on quota, different orders.
576 // Round 1 => 1L; round 2 => none, round3 => 30L.
577 TestPriorityCookieCase(cm.get(), "31L 50M 100H", 0U, 50U, 100U);
578 // Round 1 => none; round 2 => 1M, round3 => 30M.
579 TestPriorityCookieCase(cm.get(), "51M 100H 30L", 30U, 20U, 100U);
580 // Round 1 => none; round 2 => none; round3 => 31H.
581 TestPriorityCookieCase(cm.get(), "101H 50M 30L", 30U, 50U, 70U);
583 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
584 TestPriorityCookieCase(cm.get(), "81H 60M 40L", 30U, 50U, 70U);
586 // More complex scenarios.
587 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
588 TestPriorityCookieCase(cm.get(), "21H 60M 40L 60H", 30U, 50U, 70U);
589 // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
590 TestPriorityCookieCase(
591 cm.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U, 21U);
592 // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
593 TestPriorityCookieCase(cm.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U);
594 // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
595 TestPriorityCookieCase(cm.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U);
596 // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
597 TestPriorityCookieCase(cm.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U);
600 // Function for creating a CM with a number of cookies in it,
601 // no store (and hence no ability to affect access time).
602 CookieMonster* CreateMonsterForGC(int num_cookies) {
603 CookieMonster* cm(new CookieMonster(NULL, NULL));
604 for (int i = 0; i < num_cookies; i++) {
605 SetCookie(cm, GURL(base::StringPrintf("http://h%05d.izzle", i)), "a=1");
607 return cm;
611 // TODO(erikwright): Replace the other callbacks and synchronous helper methods
612 // in this test suite with these Mocks.
613 template<typename T, typename C> class MockCookieCallback {
614 public:
615 C AsCallback() {
616 return base::Bind(&T::Invoke, base::Unretained(static_cast<T*>(this)));
620 class MockGetCookiesCallback
621 : public MockCookieCallback<MockGetCookiesCallback,
622 CookieStore::GetCookiesCallback> {
623 public:
624 MOCK_METHOD1(Invoke, void(const std::string& cookies));
627 class MockSetCookiesCallback
628 : public MockCookieCallback<MockSetCookiesCallback,
629 CookieStore::SetCookiesCallback> {
630 public:
631 MOCK_METHOD1(Invoke, void(bool success));
634 class MockClosure
635 : public MockCookieCallback<MockClosure, base::Closure> {
636 public:
637 MOCK_METHOD0(Invoke, void(void));
640 class MockGetCookieListCallback
641 : public MockCookieCallback<MockGetCookieListCallback,
642 CookieMonster::GetCookieListCallback> {
643 public:
644 MOCK_METHOD1(Invoke, void(const CookieList& cookies));
647 class MockDeleteCallback
648 : public MockCookieCallback<MockDeleteCallback,
649 CookieMonster::DeleteCallback> {
650 public:
651 MOCK_METHOD1(Invoke, void(int num_deleted));
654 class MockDeleteCookieCallback
655 : public MockCookieCallback<MockDeleteCookieCallback,
656 CookieMonster::DeleteCookieCallback> {
657 public:
658 MOCK_METHOD1(Invoke, void(bool success));
661 struct CookiesInputInfo {
662 const GURL url;
663 const std::string name;
664 const std::string value;
665 const std::string domain;
666 const std::string path;
667 const base::Time expiration_time;
668 bool secure;
669 bool http_only;
670 CookiePriority priority;
673 ACTION(QuitCurrentMessageLoop) {
674 base::MessageLoop::current()->PostTask(FROM_HERE,
675 base::MessageLoop::QuitClosure());
678 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
679 // rename these, removing the 'Action' suffix.
680 ACTION_P4(DeleteCookieAction, cookie_monster, url, name, callback) {
681 cookie_monster->DeleteCookieAsync(url, name, callback->AsCallback());
683 ACTION_P3(GetCookiesAction, cookie_monster, url, callback) {
684 cookie_monster->GetCookiesWithOptionsAsync(
685 url, CookieOptions(), callback->AsCallback());
687 ACTION_P4(SetCookieAction, cookie_monster, url, cookie_line, callback) {
688 cookie_monster->SetCookieWithOptionsAsync(
689 url, cookie_line, CookieOptions(), callback->AsCallback());
691 ACTION_P4(DeleteAllCreatedBetweenAction,
692 cookie_monster, delete_begin, delete_end, callback) {
693 cookie_monster->DeleteAllCreatedBetweenAsync(
694 delete_begin, delete_end, callback->AsCallback());
696 ACTION_P3(SetCookieWithDetailsAction, cookie_monster, cc, callback) {
697 cookie_monster->SetCookieWithDetailsAsync(
698 cc.url, cc.name, cc.value, cc.domain, cc.path, cc.expiration_time,
699 cc.secure, cc.http_only, cc.priority,
700 callback->AsCallback());
703 ACTION_P2(GetAllCookiesAction, cookie_monster, callback) {
704 cookie_monster->GetAllCookiesAsync(callback->AsCallback());
707 ACTION_P3(DeleteAllForHostAction, cookie_monster, url, callback) {
708 cookie_monster->DeleteAllForHostAsync(url, callback->AsCallback());
711 ACTION_P3(DeleteCanonicalCookieAction, cookie_monster, cookie, callback) {
712 cookie_monster->DeleteCanonicalCookieAsync(cookie, callback->AsCallback());
715 ACTION_P2(DeleteAllAction, cookie_monster, callback) {
716 cookie_monster->DeleteAllAsync(callback->AsCallback());
719 ACTION_P3(GetAllCookiesForUrlWithOptionsAction, cookie_monster, url, callback) {
720 cookie_monster->GetAllCookiesForURLWithOptionsAsync(
721 url, CookieOptions(), callback->AsCallback());
724 ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) {
725 cookie_monster->GetAllCookiesForURLAsync(url, callback->AsCallback());
728 ACTION_P(PushCallbackAction, callback_vector) {
729 callback_vector->push(arg1);
732 ACTION_P2(DeleteSessionCookiesAction, cookie_monster, callback) {
733 cookie_monster->DeleteSessionCookiesAsync(callback->AsCallback());
736 } // namespace
738 // This test suite verifies the task deferral behaviour of the CookieMonster.
739 // Specifically, for each asynchronous method, verify that:
740 // 1. invoking it on an uninitialized cookie store causes the store to begin
741 // chain-loading its backing data or loading data for a specific domain key
742 // (eTLD+1).
743 // 2. The initial invocation does not complete until the loading completes.
744 // 3. Invocations after the loading has completed complete immediately.
745 class DeferredCookieTaskTest : public CookieMonsterTest {
746 protected:
747 DeferredCookieTaskTest() {
748 persistent_store_ = new NewMockPersistentCookieStore();
749 cookie_monster_ = new CookieMonster(persistent_store_.get(), NULL);
752 // Defines a cookie to be returned from PersistentCookieStore::Load
753 void DeclareLoadedCookie(const std::string& key,
754 const std::string& cookie_line,
755 const base::Time& creation_time) {
756 AddCookieToList(key, cookie_line, creation_time, &loaded_cookies_);
759 // Runs the message loop, waiting until PersistentCookieStore::Load is called.
760 // Call CompleteLoadingAndWait to cause the load to complete.
761 void WaitForLoadCall() {
762 RunFor(kTimeout);
764 // Verify that PeristentStore::Load was called.
765 testing::Mock::VerifyAndClear(persistent_store_.get());
768 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
769 // and PersistentCookieStore::Load completion callback and waits
770 // until the message loop is quit.
771 void CompleteLoadingAndWait() {
772 while (!loaded_for_key_callbacks_.empty()) {
773 loaded_for_key_callbacks_.front().Run(loaded_cookies_);
774 loaded_cookies_.clear();
775 loaded_for_key_callbacks_.pop();
778 loaded_callback_.Run(loaded_cookies_);
779 RunFor(kTimeout);
782 // Performs the provided action, expecting it to cause a call to
783 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call
784 // is received.
785 void BeginWith(testing::Action<void(void)> action) {
786 EXPECT_CALL(*this, Begin()).WillOnce(action);
787 ExpectLoadCall();
788 Begin();
791 void BeginWithForDomainKey(std::string key,
792 testing::Action<void(void)> action) {
793 EXPECT_CALL(*this, Begin()).WillOnce(action);
794 ExpectLoadCall();
795 ExpectLoadForKeyCall(key, false);
796 Begin();
799 // Declares an expectation that PersistentCookieStore::Load will be called,
800 // saving the provided callback and sending a quit to the message loop.
801 void ExpectLoadCall() {
802 EXPECT_CALL(*persistent_store_.get(), Load(testing::_))
803 .WillOnce(testing::DoAll(testing::SaveArg<0>(&loaded_callback_),
804 QuitCurrentMessageLoop()));
807 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
808 // will be called, saving the provided callback and sending a quit to the
809 // message loop.
810 void ExpectLoadForKeyCall(std::string key, bool quit_queue) {
811 if (quit_queue)
812 EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_))
813 .WillOnce(
814 testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_),
815 QuitCurrentMessageLoop()));
816 else
817 EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_))
818 .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_));
821 // Invokes the initial action.
822 MOCK_METHOD0(Begin, void(void));
824 // Returns the CookieMonster instance under test.
825 CookieMonster& cookie_monster() { return *cookie_monster_.get(); }
827 private:
828 // Declares that mock expectations in this test suite are strictly ordered.
829 testing::InSequence in_sequence_;
830 // Holds cookies to be returned from PersistentCookieStore::Load or
831 // PersistentCookieStore::LoadCookiesForKey.
832 std::vector<CanonicalCookie*> loaded_cookies_;
833 // Stores the callback passed from the CookieMonster to the
834 // PersistentCookieStore::Load
835 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_;
836 // Stores the callback passed from the CookieMonster to the
837 // PersistentCookieStore::LoadCookiesForKey
838 std::queue<CookieMonster::PersistentCookieStore::LoadedCallback>
839 loaded_for_key_callbacks_;
841 // Stores the CookieMonster under test.
842 scoped_refptr<CookieMonster> cookie_monster_;
843 // Stores the mock PersistentCookieStore.
844 scoped_refptr<NewMockPersistentCookieStore> persistent_store_;
847 TEST_F(DeferredCookieTaskTest, DeferredGetCookies) {
848 DeclareLoadedCookie("www.google.izzle",
849 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
850 Time::Now() + TimeDelta::FromDays(3));
852 MockGetCookiesCallback get_cookies_callback;
854 BeginWithForDomainKey("google.izzle", GetCookiesAction(
855 &cookie_monster(), url_google_, &get_cookies_callback));
857 WaitForLoadCall();
859 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
860 GetCookiesAction(&cookie_monster(), url_google_, &get_cookies_callback));
861 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
862 QuitCurrentMessageLoop());
864 CompleteLoadingAndWait();
867 TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {
868 MockSetCookiesCallback set_cookies_callback;
870 BeginWithForDomainKey("google.izzle", SetCookieAction(
871 &cookie_monster(), url_google_, "A=B", &set_cookies_callback));
873 WaitForLoadCall();
875 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
876 SetCookieAction(
877 &cookie_monster(), url_google_, "X=Y", &set_cookies_callback));
878 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
879 QuitCurrentMessageLoop());
881 CompleteLoadingAndWait();
884 TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) {
885 MockClosure delete_cookie_callback;
887 BeginWithForDomainKey("google.izzle", DeleteCookieAction(
888 &cookie_monster(), url_google_, "A", &delete_cookie_callback));
890 WaitForLoadCall();
892 EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce(
893 DeleteCookieAction(
894 &cookie_monster(), url_google_, "X", &delete_cookie_callback));
895 EXPECT_CALL(delete_cookie_callback, Invoke()).WillOnce(
896 QuitCurrentMessageLoop());
898 CompleteLoadingAndWait();
901 TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) {
902 MockSetCookiesCallback set_cookies_callback;
904 CookiesInputInfo cookie_info = {
905 url_google_foo_, "A", "B", std::string(), "/foo",
906 base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
908 BeginWithForDomainKey("google.izzle", SetCookieWithDetailsAction(
909 &cookie_monster(), cookie_info, &set_cookies_callback));
911 WaitForLoadCall();
913 CookiesInputInfo cookie_info_exp = {
914 url_google_foo_, "A", "B", std::string(), "/foo",
915 base::Time(), false, false, COOKIE_PRIORITY_DEFAULT
917 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
918 SetCookieWithDetailsAction(
919 &cookie_monster(), cookie_info_exp, &set_cookies_callback));
920 EXPECT_CALL(set_cookies_callback, Invoke(true)).WillOnce(
921 QuitCurrentMessageLoop());
923 CompleteLoadingAndWait();
926 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) {
927 DeclareLoadedCookie("www.google.izzle",
928 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
929 Time::Now() + TimeDelta::FromDays(3));
931 MockGetCookieListCallback get_cookie_list_callback;
933 BeginWith(GetAllCookiesAction(
934 &cookie_monster(), &get_cookie_list_callback));
936 WaitForLoadCall();
938 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
939 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback));
940 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
941 QuitCurrentMessageLoop());
943 CompleteLoadingAndWait();
946 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) {
947 DeclareLoadedCookie("www.google.izzle",
948 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
949 Time::Now() + TimeDelta::FromDays(3));
951 MockGetCookieListCallback get_cookie_list_callback;
953 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlAction(
954 &cookie_monster(), url_google_, &get_cookie_list_callback));
956 WaitForLoadCall();
958 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
959 GetAllCookiesForUrlAction(
960 &cookie_monster(), url_google_, &get_cookie_list_callback));
961 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
962 QuitCurrentMessageLoop());
964 CompleteLoadingAndWait();
967 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) {
968 DeclareLoadedCookie("www.google.izzle",
969 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
970 Time::Now() + TimeDelta::FromDays(3));
972 MockGetCookieListCallback get_cookie_list_callback;
974 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
975 &cookie_monster(), url_google_, &get_cookie_list_callback));
977 WaitForLoadCall();
979 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
980 GetAllCookiesForUrlWithOptionsAction(
981 &cookie_monster(), url_google_, &get_cookie_list_callback));
982 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_)).WillOnce(
983 QuitCurrentMessageLoop());
985 CompleteLoadingAndWait();
988 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCookies) {
989 MockDeleteCallback delete_callback;
991 BeginWith(DeleteAllAction(
992 &cookie_monster(), &delete_callback));
994 WaitForLoadCall();
996 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
997 DeleteAllAction(&cookie_monster(), &delete_callback));
998 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
999 QuitCurrentMessageLoop());
1001 CompleteLoadingAndWait();
1004 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedBetweenCookies) {
1005 MockDeleteCallback delete_callback;
1007 BeginWith(DeleteAllCreatedBetweenAction(
1008 &cookie_monster(), base::Time(), base::Time::Now(), &delete_callback));
1010 WaitForLoadCall();
1012 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1013 DeleteAllCreatedBetweenAction(
1014 &cookie_monster(), base::Time(), base::Time::Now(),
1015 &delete_callback));
1016 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1017 QuitCurrentMessageLoop());
1019 CompleteLoadingAndWait();
1022 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllForHostCookies) {
1023 MockDeleteCallback delete_callback;
1025 BeginWithForDomainKey("google.izzle", DeleteAllForHostAction(
1026 &cookie_monster(), url_google_, &delete_callback));
1028 WaitForLoadCall();
1030 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1031 DeleteAllForHostAction(
1032 &cookie_monster(), url_google_, &delete_callback));
1033 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1034 QuitCurrentMessageLoop());
1036 CompleteLoadingAndWait();
1039 TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) {
1040 std::vector<CanonicalCookie*> cookies;
1041 CanonicalCookie cookie = BuildCanonicalCookie(
1042 "www.google.com", "X=1; path=/", base::Time::Now());
1044 MockDeleteCookieCallback delete_cookie_callback;
1046 BeginWith(DeleteCanonicalCookieAction(
1047 &cookie_monster(), cookie, &delete_cookie_callback));
1049 WaitForLoadCall();
1051 EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce(
1052 DeleteCanonicalCookieAction(
1053 &cookie_monster(), cookie, &delete_cookie_callback));
1054 EXPECT_CALL(delete_cookie_callback, Invoke(false)).WillOnce(
1055 QuitCurrentMessageLoop());
1057 CompleteLoadingAndWait();
1060 TEST_F(DeferredCookieTaskTest, DeferredDeleteSessionCookies) {
1061 MockDeleteCallback delete_callback;
1063 BeginWith(DeleteSessionCookiesAction(
1064 &cookie_monster(), &delete_callback));
1066 WaitForLoadCall();
1068 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1069 DeleteSessionCookiesAction(&cookie_monster(), &delete_callback));
1070 EXPECT_CALL(delete_callback, Invoke(false)).WillOnce(
1071 QuitCurrentMessageLoop());
1073 CompleteLoadingAndWait();
1076 // Verify that a series of queued tasks are executed in order upon loading of
1077 // the backing store and that new tasks received while the queued tasks are
1078 // being dispatched go to the end of the queue.
1079 TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {
1080 DeclareLoadedCookie("www.google.izzle",
1081 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1082 Time::Now() + TimeDelta::FromDays(3));
1084 MockGetCookiesCallback get_cookies_callback;
1085 MockSetCookiesCallback set_cookies_callback;
1086 MockClosure delete_cookie_callback;
1087 MockGetCookiesCallback get_cookies_callback_deferred;
1089 EXPECT_CALL(*this, Begin()).WillOnce(testing::DoAll(
1090 GetCookiesAction(
1091 &cookie_monster(), url_google_, &get_cookies_callback),
1092 SetCookieAction(
1093 &cookie_monster(), url_google_, "A=B", &set_cookies_callback),
1094 DeleteCookieAction(
1095 &cookie_monster(), url_google_, "A", &delete_cookie_callback)));
1096 ExpectLoadCall();
1097 ExpectLoadForKeyCall("google.izzle", false);
1098 Begin();
1100 WaitForLoadCall();
1101 EXPECT_CALL(get_cookies_callback, Invoke("X=1")).WillOnce(
1102 GetCookiesAction(
1103 &cookie_monster(), url_google_, &get_cookies_callback_deferred));
1104 EXPECT_CALL(get_cookies_callback_deferred, Invoke("X=1")).WillOnce(
1105 QuitCurrentMessageLoop());
1106 EXPECT_CALL(set_cookies_callback, Invoke(true));
1107 EXPECT_CALL(delete_cookie_callback, Invoke());
1109 CompleteLoadingAndWait();
1112 TEST_F(CookieMonsterTest, TestCookieDeleteAll) {
1113 scoped_refptr<MockPersistentCookieStore> store(
1114 new MockPersistentCookieStore);
1115 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1116 CookieOptions options;
1117 options.set_include_httponly();
1119 EXPECT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
1120 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1122 EXPECT_TRUE(
1123 SetCookieWithOptions(cm.get(), url_google_, "C=D; httponly", options));
1124 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm.get(), url_google_, options));
1126 EXPECT_EQ(2, DeleteAll(cm.get()));
1127 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
1128 EXPECT_EQ(0u, store->commands().size());
1130 // Create a persistent cookie.
1131 EXPECT_TRUE(SetCookie(
1132 cm.get(),
1133 url_google_,
1134 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1135 ASSERT_EQ(1u, store->commands().size());
1136 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1138 EXPECT_EQ(1, DeleteAll(cm.get())); // sync_to_store = true.
1139 ASSERT_EQ(2u, store->commands().size());
1140 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1142 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
1145 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) {
1146 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1147 Time now = Time::Now();
1149 // Nothing has been added so nothing should be deleted.
1150 EXPECT_EQ(
1152 DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99), Time()));
1154 // Create 3 cookies with creation date of today, yesterday and the day before.
1155 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-0=Now", now));
1156 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-1=Yesterday",
1157 now - TimeDelta::FromDays(1)));
1158 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-2=DayBefore",
1159 now - TimeDelta::FromDays(2)));
1160 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-3=ThreeDays",
1161 now - TimeDelta::FromDays(3)));
1162 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-7=LastWeek",
1163 now - TimeDelta::FromDays(7)));
1165 // Try to delete threedays and the daybefore.
1166 EXPECT_EQ(2,
1167 DeleteAllCreatedBetween(cm.get(),
1168 now - TimeDelta::FromDays(3),
1169 now - TimeDelta::FromDays(1)));
1171 // Try to delete yesterday, also make sure that delete_end is not
1172 // inclusive.
1173 EXPECT_EQ(
1174 1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(2), now));
1176 // Make sure the delete_begin is inclusive.
1177 EXPECT_EQ(
1178 1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(7), now));
1180 // Delete the last (now) item.
1181 EXPECT_EQ(1, DeleteAllCreatedBetween(cm.get(), Time(), Time()));
1183 // Really make sure everything is gone.
1184 EXPECT_EQ(0, DeleteAll(cm.get()));
1187 static const int kAccessDelayMs = kLastAccessThresholdMilliseconds + 20;
1189 TEST_F(CookieMonsterTest, TestLastAccess) {
1190 scoped_refptr<CookieMonster> cm(
1191 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1193 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1194 const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
1196 // Reading the cookie again immediately shouldn't update the access date,
1197 // since we're inside the threshold.
1198 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1199 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1201 // Reading after a short wait should update the access date.
1202 base::PlatformThread::Sleep(
1203 base::TimeDelta::FromMilliseconds(kAccessDelayMs));
1204 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1205 EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1208 TEST_F(CookieMonsterTest, TestHostGarbageCollection) {
1209 TestHostGarbageCollectHelper();
1212 TEST_F(CookieMonsterTest, TestPriorityAwareGarbageCollection) {
1213 TestPriorityAwareGarbageCollectHelper();
1216 TEST_F(CookieMonsterTest, TestDeleteSingleCookie) {
1217 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1219 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1220 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
1221 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
1222 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
1224 EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
1225 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1227 EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
1228 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1231 TEST_F(CookieMonsterTest, SetCookieableSchemes) {
1232 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1233 scoped_refptr<CookieMonster> cm_foo(new CookieMonster(NULL, NULL));
1235 // Only cm_foo should allow foo:// cookies.
1236 const char* kSchemes[] = {"foo"};
1237 cm_foo->SetCookieableSchemes(kSchemes, 1);
1239 GURL foo_url("foo://host/path");
1240 GURL http_url("http://host/path");
1242 EXPECT_TRUE(SetCookie(cm.get(), http_url, "x=1"));
1243 EXPECT_FALSE(SetCookie(cm.get(), foo_url, "x=1"));
1244 EXPECT_TRUE(SetCookie(cm_foo.get(), foo_url, "x=1"));
1245 EXPECT_FALSE(SetCookie(cm_foo.get(), http_url, "x=1"));
1248 TEST_F(CookieMonsterTest, GetAllCookiesForURL) {
1249 scoped_refptr<CookieMonster> cm(
1250 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1252 // Create an httponly cookie.
1253 CookieOptions options;
1254 options.set_include_httponly();
1256 EXPECT_TRUE(
1257 SetCookieWithOptions(cm.get(), url_google_, "A=B; httponly", options));
1258 EXPECT_TRUE(SetCookieWithOptions(
1259 cm.get(), url_google_, "C=D; domain=.google.izzle", options));
1260 EXPECT_TRUE(SetCookieWithOptions(cm.get(),
1261 url_google_secure_,
1262 "E=F; domain=.google.izzle; secure",
1263 options));
1265 const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
1267 base::PlatformThread::Sleep(
1268 base::TimeDelta::FromMilliseconds(kAccessDelayMs));
1270 // Check cookies for url.
1271 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
1272 CookieList::iterator it = cookies.begin();
1274 ASSERT_TRUE(it != cookies.end());
1275 EXPECT_EQ("www.google.izzle", it->Domain());
1276 EXPECT_EQ("A", it->Name());
1278 ASSERT_TRUE(++it != cookies.end());
1279 EXPECT_EQ(".google.izzle", it->Domain());
1280 EXPECT_EQ("C", it->Name());
1282 ASSERT_TRUE(++it == cookies.end());
1284 // Check cookies for url excluding http-only cookies.
1285 cookies =
1286 GetAllCookiesForURLWithOptions(cm.get(), url_google_, CookieOptions());
1287 it = cookies.begin();
1289 ASSERT_TRUE(it != cookies.end());
1290 EXPECT_EQ(".google.izzle", it->Domain());
1291 EXPECT_EQ("C", it->Name());
1293 ASSERT_TRUE(++it == cookies.end());
1295 // Test secure cookies.
1296 cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
1297 it = cookies.begin();
1299 ASSERT_TRUE(it != cookies.end());
1300 EXPECT_EQ("www.google.izzle", it->Domain());
1301 EXPECT_EQ("A", it->Name());
1303 ASSERT_TRUE(++it != cookies.end());
1304 EXPECT_EQ(".google.izzle", it->Domain());
1305 EXPECT_EQ("C", it->Name());
1307 ASSERT_TRUE(++it != cookies.end());
1308 EXPECT_EQ(".google.izzle", it->Domain());
1309 EXPECT_EQ("E", it->Name());
1311 ASSERT_TRUE(++it == cookies.end());
1313 // Reading after a short wait should not update the access date.
1314 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1317 TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
1318 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1319 CookieOptions options;
1321 EXPECT_TRUE(SetCookieWithOptions(
1322 cm.get(), url_google_foo_, "A=B; path=/foo;", options));
1323 EXPECT_TRUE(SetCookieWithOptions(
1324 cm.get(), url_google_bar_, "C=D; path=/bar;", options));
1325 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "E=F;", options));
1327 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
1328 CookieList::iterator it = cookies.begin();
1330 ASSERT_TRUE(it != cookies.end());
1331 EXPECT_EQ("A", it->Name());
1332 EXPECT_EQ("/foo", it->Path());
1334 ASSERT_TRUE(++it != cookies.end());
1335 EXPECT_EQ("E", it->Name());
1336 EXPECT_EQ("/", it->Path());
1338 ASSERT_TRUE(++it == cookies.end());
1340 cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
1341 it = cookies.begin();
1343 ASSERT_TRUE(it != cookies.end());
1344 EXPECT_EQ("C", it->Name());
1345 EXPECT_EQ("/bar", it->Path());
1347 ASSERT_TRUE(++it != cookies.end());
1348 EXPECT_EQ("E", it->Name());
1349 EXPECT_EQ("/", it->Path());
1351 ASSERT_TRUE(++it == cookies.end());
1354 TEST_F(CookieMonsterTest, DeleteCookieByName) {
1355 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1357 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A1; path=/"));
1358 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A2; path=/foo"));
1359 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A3; path=/bar"));
1360 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B1; path=/"));
1361 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B2; path=/foo"));
1362 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/bar"));
1364 DeleteCookie(cm.get(), GURL(std::string(kUrlGoogle) + "/foo/bar"), "A");
1366 CookieList cookies = GetAllCookies(cm.get());
1367 size_t expected_size = 4;
1368 EXPECT_EQ(expected_size, cookies.size());
1369 for (CookieList::iterator it = cookies.begin();
1370 it != cookies.end(); ++it) {
1371 EXPECT_NE("A1", it->Value());
1372 EXPECT_NE("A2", it->Value());
1376 TEST_F(CookieMonsterTest, InitializeFromCookieMonster) {
1377 scoped_refptr<CookieMonster> cm_1(new CookieMonster(NULL, NULL));
1378 CookieOptions options;
1380 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_foo_,
1381 "A1=B; path=/foo;",
1382 options));
1383 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_bar_,
1384 "A2=D; path=/bar;",
1385 options));
1386 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_,
1387 "A3=F;",
1388 options));
1390 CookieList cookies_1 = GetAllCookies(cm_1.get());
1391 scoped_refptr<CookieMonster> cm_2(new CookieMonster(NULL, NULL));
1392 ASSERT_TRUE(cm_2->InitializeFrom(cookies_1));
1393 CookieList cookies_2 = GetAllCookies(cm_2.get());
1395 size_t expected_size = 3;
1396 EXPECT_EQ(expected_size, cookies_2.size());
1398 CookieList::iterator it = cookies_2.begin();
1400 ASSERT_TRUE(it != cookies_2.end());
1401 EXPECT_EQ("A1", it->Name());
1402 EXPECT_EQ("/foo", it->Path());
1404 ASSERT_TRUE(++it != cookies_2.end());
1405 EXPECT_EQ("A2", it->Name());
1406 EXPECT_EQ("/bar", it->Path());
1408 ASSERT_TRUE(++it != cookies_2.end());
1409 EXPECT_EQ("A3", it->Name());
1410 EXPECT_EQ("/", it->Path());
1413 // Tests importing from a persistent cookie store that contains duplicate
1414 // equivalent cookies. This situation should be handled by removing the
1415 // duplicate cookie (both from the in-memory cache, and from the backing store).
1417 // This is a regression test for: http://crbug.com/17855.
1418 TEST_F(CookieMonsterTest, DontImportDuplicateCookies) {
1419 scoped_refptr<MockPersistentCookieStore> store(
1420 new MockPersistentCookieStore);
1422 // We will fill some initial cookies into the PersistentCookieStore,
1423 // to simulate a database with 4 duplicates. Note that we need to
1424 // be careful not to have any duplicate creation times at all (as it's a
1425 // violation of a CookieMonster invariant) even if Time::Now() doesn't
1426 // move between calls.
1427 std::vector<CanonicalCookie*> initial_cookies;
1429 // Insert 4 cookies with name "X" on path "/", with varying creation
1430 // dates. We expect only the most recent one to be preserved following
1431 // the import.
1433 AddCookieToList("www.google.com",
1434 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1435 Time::Now() + TimeDelta::FromDays(3),
1436 &initial_cookies);
1438 AddCookieToList("www.google.com",
1439 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1440 Time::Now() + TimeDelta::FromDays(1),
1441 &initial_cookies);
1443 // ===> This one is the WINNER (biggest creation time). <====
1444 AddCookieToList("www.google.com",
1445 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1446 Time::Now() + TimeDelta::FromDays(4),
1447 &initial_cookies);
1449 AddCookieToList("www.google.com",
1450 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1451 Time::Now(),
1452 &initial_cookies);
1454 // Insert 2 cookies with name "X" on path "/2", with varying creation
1455 // dates. We expect only the most recent one to be preserved the import.
1457 // ===> This one is the WINNER (biggest creation time). <====
1458 AddCookieToList("www.google.com",
1459 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1460 Time::Now() + TimeDelta::FromDays(9),
1461 &initial_cookies);
1463 AddCookieToList("www.google.com",
1464 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1465 Time::Now() + TimeDelta::FromDays(2),
1466 &initial_cookies);
1468 // Insert 1 cookie with name "Y" on path "/".
1469 AddCookieToList("www.google.com",
1470 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1471 Time::Now() + TimeDelta::FromDays(10),
1472 &initial_cookies);
1474 // Inject our initial cookies into the mock PersistentCookieStore.
1475 store->SetLoadExpectation(true, initial_cookies);
1477 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1479 // Verify that duplicates were not imported for path "/".
1480 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1481 EXPECT_EQ("X=3; Y=a", GetCookies(cm.get(), GURL("http://www.google.com/")));
1483 // Verify that same-named cookie on a different path ("/x2") didn't get
1484 // messed up.
1485 EXPECT_EQ("X=a1; X=3; Y=a",
1486 GetCookies(cm.get(), GURL("http://www.google.com/2/x")));
1488 // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1489 ASSERT_EQ(4u, store->commands().size());
1490 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type);
1491 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1492 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
1493 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
1496 // Tests importing from a persistent cookie store that contains cookies
1497 // with duplicate creation times. This situation should be handled by
1498 // dropping the cookies before insertion/visibility to user.
1500 // This is a regression test for: http://crbug.com/43188.
1501 TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) {
1502 scoped_refptr<MockPersistentCookieStore> store(
1503 new MockPersistentCookieStore);
1505 Time now(Time::Now());
1506 Time earlier(now - TimeDelta::FromDays(1));
1508 // Insert 8 cookies, four with the current time as creation times, and
1509 // four with the earlier time as creation times. We should only get
1510 // two cookies remaining, but which two (other than that there should
1511 // be one from each set) will be random.
1512 std::vector<CanonicalCookie*> initial_cookies;
1513 AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies);
1514 AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies);
1515 AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies);
1516 AddCookieToList("www.google.com", "X=4; path=/", now, &initial_cookies);
1518 AddCookieToList("www.google.com", "Y=1; path=/", earlier, &initial_cookies);
1519 AddCookieToList("www.google.com", "Y=2; path=/", earlier, &initial_cookies);
1520 AddCookieToList("www.google.com", "Y=3; path=/", earlier, &initial_cookies);
1521 AddCookieToList("www.google.com", "Y=4; path=/", earlier, &initial_cookies);
1523 // Inject our initial cookies into the mock PersistentCookieStore.
1524 store->SetLoadExpectation(true, initial_cookies);
1526 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1528 CookieList list(GetAllCookies(cm.get()));
1529 EXPECT_EQ(2U, list.size());
1530 // Confirm that we have one of each.
1531 std::string name1(list[0].Name());
1532 std::string name2(list[1].Name());
1533 EXPECT_TRUE(name1 == "X" || name2 == "X");
1534 EXPECT_TRUE(name1 == "Y" || name2 == "Y");
1535 EXPECT_NE(name1, name2);
1538 TEST_F(CookieMonsterTest, Delegate) {
1539 scoped_refptr<MockPersistentCookieStore> store(
1540 new MockPersistentCookieStore);
1541 scoped_refptr<MockCookieMonsterDelegate> delegate(
1542 new MockCookieMonsterDelegate);
1543 scoped_refptr<CookieMonster> cm(
1544 new CookieMonster(store.get(), delegate.get()));
1546 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1547 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
1548 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
1549 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
1550 ASSERT_EQ(3u, delegate->changes().size());
1551 EXPECT_FALSE(delegate->changes()[0].second);
1552 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1553 EXPECT_EQ("A", delegate->changes()[0].first.Name());
1554 EXPECT_EQ("B", delegate->changes()[0].first.Value());
1555 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
1556 EXPECT_FALSE(delegate->changes()[1].second);
1557 EXPECT_EQ("C", delegate->changes()[1].first.Name());
1558 EXPECT_EQ("D", delegate->changes()[1].first.Value());
1559 EXPECT_EQ(url_google_.host(), delegate->changes()[2].first.Domain());
1560 EXPECT_FALSE(delegate->changes()[2].second);
1561 EXPECT_EQ("E", delegate->changes()[2].first.Name());
1562 EXPECT_EQ("F", delegate->changes()[2].first.Value());
1563 delegate->reset();
1565 EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
1566 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1567 ASSERT_EQ(1u, delegate->changes().size());
1568 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1569 EXPECT_TRUE(delegate->changes()[0].second);
1570 EXPECT_EQ("C", delegate->changes()[0].first.Name());
1571 EXPECT_EQ("D", delegate->changes()[0].first.Value());
1572 delegate->reset();
1574 EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
1575 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1576 EXPECT_EQ(0u, delegate->changes().size());
1578 // Insert a cookie "a" for path "/path1"
1579 EXPECT_TRUE(SetCookie(cm.get(),
1580 url_google_,
1581 "a=val1; path=/path1; "
1582 "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1583 ASSERT_EQ(1u, store->commands().size());
1584 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1585 ASSERT_EQ(1u, delegate->changes().size());
1586 EXPECT_FALSE(delegate->changes()[0].second);
1587 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1588 EXPECT_EQ("a", delegate->changes()[0].first.Name());
1589 EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1590 delegate->reset();
1592 // Insert a cookie "a" for path "/path1", that is httponly. This should
1593 // overwrite the non-http-only version.
1594 CookieOptions allow_httponly;
1595 allow_httponly.set_include_httponly();
1596 EXPECT_TRUE(SetCookieWithOptions(cm.get(),
1597 url_google_,
1598 "a=val2; path=/path1; httponly; "
1599 "expires=Mon, 18-Apr-22 22:50:14 GMT",
1600 allow_httponly));
1601 ASSERT_EQ(3u, store->commands().size());
1602 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1603 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
1604 ASSERT_EQ(2u, delegate->changes().size());
1605 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1606 EXPECT_TRUE(delegate->changes()[0].second);
1607 EXPECT_EQ("a", delegate->changes()[0].first.Name());
1608 EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1609 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
1610 EXPECT_FALSE(delegate->changes()[1].second);
1611 EXPECT_EQ("a", delegate->changes()[1].first.Name());
1612 EXPECT_EQ("val2", delegate->changes()[1].first.Value());
1613 delegate->reset();
1616 TEST_F(CookieMonsterTest, SetCookieWithDetails) {
1617 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1619 EXPECT_TRUE(SetCookieWithDetails(cm.get(),
1620 url_google_foo_,
1621 "A",
1622 "B",
1623 std::string(),
1624 "/foo",
1625 base::Time(),
1626 false,
1627 false,
1628 COOKIE_PRIORITY_DEFAULT));
1629 EXPECT_TRUE(SetCookieWithDetails(cm.get(),
1630 url_google_bar_,
1631 "C",
1632 "D",
1633 "google.izzle",
1634 "/bar",
1635 base::Time(),
1636 false,
1637 true,
1638 COOKIE_PRIORITY_DEFAULT));
1639 EXPECT_TRUE(SetCookieWithDetails(cm.get(),
1640 url_google_,
1641 "E",
1642 "F",
1643 std::string(),
1644 std::string(),
1645 base::Time(),
1646 true,
1647 false,
1648 COOKIE_PRIORITY_DEFAULT));
1650 // Test that malformed attributes fail to set the cookie.
1651 EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1652 url_google_foo_,
1653 " A",
1654 "B",
1655 std::string(),
1656 "/foo",
1657 base::Time(),
1658 false,
1659 false,
1660 COOKIE_PRIORITY_DEFAULT));
1661 EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1662 url_google_foo_,
1663 "A;",
1664 "B",
1665 std::string(),
1666 "/foo",
1667 base::Time(),
1668 false,
1669 false,
1670 COOKIE_PRIORITY_DEFAULT));
1671 EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1672 url_google_foo_,
1673 "A=",
1674 "B",
1675 std::string(),
1676 "/foo",
1677 base::Time(),
1678 false,
1679 false,
1680 COOKIE_PRIORITY_DEFAULT));
1681 EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1682 url_google_foo_,
1683 "A",
1684 "B",
1685 "google.ozzzzzzle",
1686 "foo",
1687 base::Time(),
1688 false,
1689 false,
1690 COOKIE_PRIORITY_DEFAULT));
1691 EXPECT_FALSE(SetCookieWithDetails(cm.get(),
1692 url_google_foo_,
1693 "A=",
1694 "B",
1695 std::string(),
1696 "foo",
1697 base::Time(),
1698 false,
1699 false,
1700 COOKIE_PRIORITY_DEFAULT));
1702 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
1703 CookieList::iterator it = cookies.begin();
1705 ASSERT_TRUE(it != cookies.end());
1706 EXPECT_EQ("A", it->Name());
1707 EXPECT_EQ("B", it->Value());
1708 EXPECT_EQ("www.google.izzle", it->Domain());
1709 EXPECT_EQ("/foo", it->Path());
1710 EXPECT_FALSE(it->IsPersistent());
1711 EXPECT_FALSE(it->IsSecure());
1712 EXPECT_FALSE(it->IsHttpOnly());
1714 ASSERT_TRUE(++it == cookies.end());
1716 cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
1717 it = cookies.begin();
1719 ASSERT_TRUE(it != cookies.end());
1720 EXPECT_EQ("C", it->Name());
1721 EXPECT_EQ("D", it->Value());
1722 EXPECT_EQ(".google.izzle", it->Domain());
1723 EXPECT_EQ("/bar", it->Path());
1724 EXPECT_FALSE(it->IsSecure());
1725 EXPECT_TRUE(it->IsHttpOnly());
1727 ASSERT_TRUE(++it == cookies.end());
1729 cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
1730 it = cookies.begin();
1732 ASSERT_TRUE(it != cookies.end());
1733 EXPECT_EQ("E", it->Name());
1734 EXPECT_EQ("F", it->Value());
1735 EXPECT_EQ("/", it->Path());
1736 EXPECT_EQ("www.google.izzle", it->Domain());
1737 EXPECT_TRUE(it->IsSecure());
1738 EXPECT_FALSE(it->IsHttpOnly());
1740 ASSERT_TRUE(++it == cookies.end());
1743 TEST_F(CookieMonsterTest, DeleteAllForHost) {
1744 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1746 // Test probes:
1747 // * Non-secure URL, mid-level (http://w.c.b.a)
1748 // * Secure URL, mid-level (https://w.c.b.a)
1749 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1750 // All three tests should nuke only the midlevel host cookie,
1751 // the http_only cookie, the host secure cookie, and the two host
1752 // path cookies. http_only, secure, and paths are ignored by
1753 // this call, and domain cookies arent touched.
1754 PopulateCmForDeleteAllForHost(cm);
1755 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1756 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1757 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1758 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1759 EXPECT_EQ("dom_1=X; host_1=X",
1760 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1761 EXPECT_EQ("dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1762 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1763 GetCookies(cm.get(),
1764 GURL(kTopLevelDomainPlus2Secure +
1765 std::string("/dir1/dir2/xxx"))));
1767 EXPECT_EQ(5, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2)));
1768 EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1770 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1771 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1772 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1773 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1774 EXPECT_EQ("dom_1=X; host_1=X",
1775 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1776 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1777 GetCookies(cm.get(),
1778 GURL(kTopLevelDomainPlus2Secure +
1779 std::string("/dir1/dir2/xxx"))));
1781 PopulateCmForDeleteAllForHost(cm);
1782 EXPECT_EQ(5, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1783 EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1785 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1786 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1787 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1788 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1789 EXPECT_EQ("dom_1=X; host_1=X",
1790 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1791 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1792 GetCookies(cm.get(),
1793 GURL(kTopLevelDomainPlus2Secure +
1794 std::string("/dir1/dir2/xxx"))));
1796 PopulateCmForDeleteAllForHost(cm);
1797 EXPECT_EQ(5,
1798 DeleteAllForHost(
1799 cm.get(),
1800 GURL(kTopLevelDomainPlus2Secure + std::string("/dir1/xxx"))));
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"))));
1815 TEST_F(CookieMonsterTest, UniqueCreationTime) {
1816 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1817 CookieOptions options;
1819 // Add in three cookies through every public interface to the
1820 // CookieMonster and confirm that none of them have duplicate
1821 // creation times.
1823 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1824 // are not included as they aren't going to be public for very much
1825 // longer.
1827 // SetCookie, SetCookieWithOptions, SetCookieWithDetails
1829 SetCookie(cm.get(), url_google_, "SetCookie1=A");
1830 SetCookie(cm.get(), url_google_, "SetCookie2=A");
1831 SetCookie(cm.get(), url_google_, "SetCookie3=A");
1833 SetCookieWithOptions(
1834 cm.get(), url_google_, "setCookieWithOptions1=A", options);
1835 SetCookieWithOptions(
1836 cm.get(), url_google_, "setCookieWithOptions2=A", options);
1837 SetCookieWithOptions(
1838 cm.get(), url_google_, "setCookieWithOptions3=A", options);
1840 SetCookieWithDetails(cm.get(),
1841 url_google_,
1842 "setCookieWithDetails1",
1843 "A",
1844 ".google.com",
1845 "/",
1846 Time(),
1847 false,
1848 false,
1849 COOKIE_PRIORITY_DEFAULT);
1850 SetCookieWithDetails(cm.get(),
1851 url_google_,
1852 "setCookieWithDetails2",
1853 "A",
1854 ".google.com",
1855 "/",
1856 Time(),
1857 false,
1858 false,
1859 COOKIE_PRIORITY_DEFAULT);
1860 SetCookieWithDetails(cm.get(),
1861 url_google_,
1862 "setCookieWithDetails3",
1863 "A",
1864 ".google.com",
1865 "/",
1866 Time(),
1867 false,
1868 false,
1869 COOKIE_PRIORITY_DEFAULT);
1871 // Now we check
1872 CookieList cookie_list(GetAllCookies(cm.get()));
1873 typedef std::map<int64, CanonicalCookie> TimeCookieMap;
1874 TimeCookieMap check_map;
1875 for (CookieList::const_iterator it = cookie_list.begin();
1876 it != cookie_list.end(); it++) {
1877 const int64 creation_date = it->CreationDate().ToInternalValue();
1878 TimeCookieMap::const_iterator
1879 existing_cookie_it(check_map.find(creation_date));
1880 EXPECT_TRUE(existing_cookie_it == check_map.end())
1881 << "Cookie " << it->Name() << " has same creation date ("
1882 << it->CreationDate().ToInternalValue()
1883 << ") as previously entered cookie "
1884 << existing_cookie_it->second.Name();
1886 if (existing_cookie_it == check_map.end()) {
1887 check_map.insert(TimeCookieMap::value_type(
1888 it->CreationDate().ToInternalValue(), *it));
1893 // Mainly a test of GetEffectiveDomain, or more specifically, of the
1894 // expected behavior of GetEffectiveDomain within the CookieMonster.
1895 TEST_F(CookieMonsterTest, GetKey) {
1896 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1898 // This test is really only interesting if GetKey() actually does something.
1899 EXPECT_EQ("google.com", cm->GetKey("www.google.com"));
1900 EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie"));
1901 EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie"));
1902 EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk"));
1903 EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk"));
1904 EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com"));
1905 EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie"));
1907 // Cases where the effective domain is null, so we use the host
1908 // as the key.
1909 EXPECT_EQ("co.uk", cm->GetKey("co.uk"));
1910 const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1911 EXPECT_EQ(extension_name, cm->GetKey(extension_name));
1912 EXPECT_EQ("com", cm->GetKey("com"));
1913 EXPECT_EQ("hostalias", cm->GetKey("hostalias"));
1914 EXPECT_EQ("localhost", cm->GetKey("localhost"));
1917 // Test that cookies transfer from/to the backing store correctly.
1918 TEST_F(CookieMonsterTest, BackingStoreCommunication) {
1919 // Store details for cookies transforming through the backing store interface.
1921 base::Time current(base::Time::Now());
1922 scoped_refptr<MockSimplePersistentCookieStore> store(
1923 new MockSimplePersistentCookieStore);
1924 base::Time new_access_time;
1925 base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1927 const CookiesInputInfo input_info[] = {
1928 {GURL("http://a.b.google.com"), "a", "1", "", "/path/to/cookie", expires,
1929 false, false, COOKIE_PRIORITY_DEFAULT},
1930 {GURL("https://www.google.com"), "b", "2", ".google.com",
1931 "/path/from/cookie", expires + TimeDelta::FromSeconds(10),
1932 true, true, COOKIE_PRIORITY_DEFAULT},
1933 {GURL("https://google.com"), "c", "3", "", "/another/path/to/cookie",
1934 base::Time::Now() + base::TimeDelta::FromSeconds(100),
1935 true, false, COOKIE_PRIORITY_DEFAULT}
1937 const int INPUT_DELETE = 1;
1939 // Create new cookies and flush them to the store.
1941 scoped_refptr<CookieMonster> cmout(new CookieMonster(store.get(), NULL));
1942 for (const CookiesInputInfo* p = input_info;
1943 p < &input_info[ARRAYSIZE_UNSAFE(input_info)];
1944 p++) {
1945 EXPECT_TRUE(SetCookieWithDetails(cmout.get(),
1946 p->url,
1947 p->name,
1948 p->value,
1949 p->domain,
1950 p->path,
1951 p->expiration_time,
1952 p->secure,
1953 p->http_only,
1954 p->priority));
1956 GURL del_url(input_info[INPUT_DELETE].url.Resolve(
1957 input_info[INPUT_DELETE].path).spec());
1958 DeleteCookie(cmout.get(), del_url, input_info[INPUT_DELETE].name);
1961 // Create a new cookie monster and make sure that everything is correct
1963 scoped_refptr<CookieMonster> cmin(new CookieMonster(store.get(), NULL));
1964 CookieList cookies(GetAllCookies(cmin.get()));
1965 ASSERT_EQ(2u, cookies.size());
1966 // Ordering is path length, then creation time. So second cookie
1967 // will come first, and we need to swap them.
1968 std::swap(cookies[0], cookies[1]);
1969 for (int output_index = 0; output_index < 2; output_index++) {
1970 int input_index = output_index * 2;
1971 const CookiesInputInfo* input = &input_info[input_index];
1972 const CanonicalCookie* output = &cookies[output_index];
1974 EXPECT_EQ(input->name, output->Name());
1975 EXPECT_EQ(input->value, output->Value());
1976 EXPECT_EQ(input->url.host(), output->Domain());
1977 EXPECT_EQ(input->path, output->Path());
1978 EXPECT_LE(current.ToInternalValue(),
1979 output->CreationDate().ToInternalValue());
1980 EXPECT_EQ(input->secure, output->IsSecure());
1981 EXPECT_EQ(input->http_only, output->IsHttpOnly());
1982 EXPECT_TRUE(output->IsPersistent());
1983 EXPECT_EQ(input->expiration_time.ToInternalValue(),
1984 output->ExpiryDate().ToInternalValue());
1989 TEST_F(CookieMonsterTest, CookieListOrdering) {
1990 // Put a random set of cookies into a monster and make sure
1991 // they're returned in the right order.
1992 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1993 EXPECT_TRUE(
1994 SetCookie(cm.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1"));
1995 EXPECT_TRUE(SetCookie(cm.get(),
1996 GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1997 "d=1; domain=b.a.google.com"));
1998 EXPECT_TRUE(SetCookie(cm.get(),
1999 GURL("http://b.a.google.com/aa/bb/cc/x.html"),
2000 "a=4; domain=b.a.google.com"));
2001 EXPECT_TRUE(SetCookie(cm.get(),
2002 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
2003 "e=1; domain=c.b.a.google.com"));
2004 EXPECT_TRUE(SetCookie(
2005 cm.get(), GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1"));
2006 EXPECT_TRUE(SetCookie(
2007 cm.get(), GURL("http://news.bbc.co.uk/midpath/x.html"), "g=10"));
2009 unsigned int i = 0;
2010 CookieList cookies(GetAllCookiesForURL(
2011 cm.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
2012 ASSERT_EQ(5u, cookies.size());
2013 EXPECT_EQ("d", cookies[i++].Name());
2014 EXPECT_EQ("a", cookies[i++].Name());
2015 EXPECT_EQ("e", cookies[i++].Name());
2016 EXPECT_EQ("b", cookies[i++].Name());
2017 EXPECT_EQ("c", cookies[i++].Name());
2021 unsigned int i = 0;
2022 CookieList cookies(GetAllCookies(cm.get()));
2023 ASSERT_EQ(6u, cookies.size());
2024 EXPECT_EQ("d", cookies[i++].Name());
2025 EXPECT_EQ("a", cookies[i++].Name());
2026 EXPECT_EQ("e", cookies[i++].Name());
2027 EXPECT_EQ("g", cookies[i++].Name());
2028 EXPECT_EQ("b", cookies[i++].Name());
2029 EXPECT_EQ("c", cookies[i++].Name());
2033 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
2034 // are somewhat complementary twins. This test is probing for whether
2035 // garbage collection always happens when it should (i.e. that we actually
2036 // get rid of cookies when we should). The perftest is probing for
2037 // whether garbage collection happens when it shouldn't. See comments
2038 // before that test for more details.
2040 // Disabled on Windows, see crbug.com/126095
2041 #if defined(OS_WIN)
2042 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers
2043 #else
2044 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers
2045 #endif
2047 TEST_F(CookieMonsterTest, MAYBE_GarbageCollectionTriggers) {
2048 // First we check to make sure that a whole lot of recent cookies
2049 // doesn't get rid of anything after garbage collection is checked for.
2051 scoped_refptr<CookieMonster> cm(
2052 CreateMonsterForGC(CookieMonster::kMaxCookies * 2));
2053 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
2054 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
2055 EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1,
2056 GetAllCookies(cm.get()).size());
2059 // Now we explore a series of relationships between cookie last access
2060 // time and size of store to make sure we only get rid of cookies when
2061 // we really should.
2062 const struct TestCase {
2063 size_t num_cookies;
2064 size_t num_old_cookies;
2065 size_t expected_initial_cookies;
2066 // Indexed by ExpiryAndKeyScheme
2067 size_t expected_cookies_after_set;
2068 } test_cases[] = {
2070 // A whole lot of recent cookies; gc shouldn't happen.
2071 CookieMonster::kMaxCookies * 2,
2073 CookieMonster::kMaxCookies * 2,
2074 CookieMonster::kMaxCookies * 2 + 1
2075 }, {
2076 // Some old cookies, but still overflowing max.
2077 CookieMonster::kMaxCookies * 2,
2078 CookieMonster::kMaxCookies / 2,
2079 CookieMonster::kMaxCookies * 2,
2080 CookieMonster::kMaxCookies * 2 - CookieMonster::kMaxCookies / 2 + 1
2081 }, {
2082 // Old cookies enough to bring us right down to our purge line.
2083 CookieMonster::kMaxCookies * 2,
2084 CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies + 1,
2085 CookieMonster::kMaxCookies * 2,
2086 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies
2087 }, {
2088 // Old cookies enough to bring below our purge line (which we
2089 // shouldn't do).
2090 CookieMonster::kMaxCookies * 2,
2091 CookieMonster::kMaxCookies * 3 / 2,
2092 CookieMonster::kMaxCookies * 2,
2093 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies
2097 for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) {
2098 const TestCase *test_case = &test_cases[ci];
2099 scoped_refptr<CookieMonster> cm(
2100 CreateMonsterFromStoreForGC(
2101 test_case->num_cookies, test_case->num_old_cookies,
2102 CookieMonster::kSafeFromGlobalPurgeDays * 2));
2103 EXPECT_EQ(test_case->expected_initial_cookies,
2104 GetAllCookies(cm.get()).size()) << "For test case " << ci;
2105 // Will trigger GC
2106 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
2107 EXPECT_EQ(test_case->expected_cookies_after_set,
2108 GetAllCookies(cm.get()).size()) << "For test case " << ci;
2112 // This test checks that keep expired cookies flag is working.
2113 TEST_F(CookieMonsterTest, KeepExpiredCookies) {
2114 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2115 cm->SetKeepExpiredCookies();
2116 CookieOptions options;
2118 // Set a persistent cookie.
2119 ASSERT_TRUE(SetCookieWithOptions(
2120 cm.get(),
2121 url_google_,
2122 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2123 options));
2125 // Get the canonical cookie.
2126 CookieList cookie_list = GetAllCookies(cm.get());
2127 ASSERT_EQ(1U, cookie_list.size());
2129 // Use a past expiry date to delete the cookie.
2130 ASSERT_TRUE(SetCookieWithOptions(
2131 cm.get(),
2132 url_google_,
2133 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2134 options));
2136 // Check that the cookie with the past expiry date is still there.
2137 // GetAllCookies() also triggers garbage collection.
2138 cookie_list = GetAllCookies(cm.get());
2139 ASSERT_EQ(1U, cookie_list.size());
2140 ASSERT_TRUE(cookie_list[0].IsExpired(Time::Now()));
2143 namespace {
2145 // Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2146 class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
2147 public:
2148 FlushablePersistentStore() : flush_count_(0) {}
2150 virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE {
2151 std::vector<CanonicalCookie*> out_cookies;
2152 base::MessageLoop::current()->PostTask(
2153 FROM_HERE,
2154 base::Bind(&net::LoadedCallbackTask::Run,
2155 new net::LoadedCallbackTask(loaded_callback, out_cookies)));
2158 virtual void LoadCookiesForKey(
2159 const std::string& key,
2160 const LoadedCallback& loaded_callback) OVERRIDE {
2161 Load(loaded_callback);
2164 virtual void AddCookie(const CanonicalCookie&) OVERRIDE {}
2165 virtual void UpdateCookieAccessTime(const CanonicalCookie&) OVERRIDE {}
2166 virtual void DeleteCookie(const CanonicalCookie&) OVERRIDE {}
2167 virtual void SetForceKeepSessionState() OVERRIDE {}
2169 virtual void Flush(const base::Closure& callback) OVERRIDE {
2170 ++flush_count_;
2171 if (!callback.is_null())
2172 callback.Run();
2175 int flush_count() {
2176 return flush_count_;
2179 private:
2180 virtual ~FlushablePersistentStore() {}
2182 volatile int flush_count_;
2185 // Counts the number of times Callback() has been run.
2186 class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> {
2187 public:
2188 CallbackCounter() : callback_count_(0) {}
2190 void Callback() {
2191 ++callback_count_;
2194 int callback_count() {
2195 return callback_count_;
2198 private:
2199 friend class base::RefCountedThreadSafe<CallbackCounter>;
2200 ~CallbackCounter() {}
2202 volatile int callback_count_;
2205 } // namespace
2207 // Test that FlushStore() is forwarded to the store and callbacks are posted.
2208 TEST_F(CookieMonsterTest, FlushStore) {
2209 scoped_refptr<CallbackCounter> counter(new CallbackCounter());
2210 scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
2211 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2213 ASSERT_EQ(0, store->flush_count());
2214 ASSERT_EQ(0, counter->callback_count());
2216 // Before initialization, FlushStore() should just run the callback.
2217 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2218 base::MessageLoop::current()->RunUntilIdle();
2220 ASSERT_EQ(0, store->flush_count());
2221 ASSERT_EQ(1, counter->callback_count());
2223 // NULL callback is safe.
2224 cm->FlushStore(base::Closure());
2225 base::MessageLoop::current()->RunUntilIdle();
2227 ASSERT_EQ(0, store->flush_count());
2228 ASSERT_EQ(1, counter->callback_count());
2230 // After initialization, FlushStore() should delegate to the store.
2231 GetAllCookies(cm.get()); // Force init.
2232 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2233 base::MessageLoop::current()->RunUntilIdle();
2235 ASSERT_EQ(1, store->flush_count());
2236 ASSERT_EQ(2, counter->callback_count());
2238 // NULL callback is still safe.
2239 cm->FlushStore(base::Closure());
2240 base::MessageLoop::current()->RunUntilIdle();
2242 ASSERT_EQ(2, store->flush_count());
2243 ASSERT_EQ(2, counter->callback_count());
2245 // If there's no backing store, FlushStore() is always a safe no-op.
2246 cm = new CookieMonster(NULL, NULL);
2247 GetAllCookies(cm.get()); // Force init.
2248 cm->FlushStore(base::Closure());
2249 base::MessageLoop::current()->RunUntilIdle();
2251 ASSERT_EQ(2, counter->callback_count());
2253 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2254 base::MessageLoop::current()->RunUntilIdle();
2256 ASSERT_EQ(3, counter->callback_count());
2259 TEST_F(CookieMonsterTest, HistogramCheck) {
2260 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2261 // Should match call in InitializeHistograms, but doesn't really matter
2262 // since the histogram should have been initialized by the CM construction
2263 // above.
2264 base::HistogramBase* expired_histogram =
2265 base::Histogram::FactoryGet(
2266 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2267 base::Histogram::kUmaTargetedHistogramFlag);
2269 scoped_ptr<base::HistogramSamples> samples1(
2270 expired_histogram->SnapshotSamples());
2271 ASSERT_TRUE(
2272 SetCookieWithDetails(cm.get(),
2273 GURL("http://fake.a.url"),
2274 "a",
2275 "b",
2276 "a.url",
2277 "/",
2278 base::Time::Now() + base::TimeDelta::FromMinutes(59),
2279 false,
2280 false,
2281 COOKIE_PRIORITY_DEFAULT));
2283 scoped_ptr<base::HistogramSamples> samples2(
2284 expired_histogram->SnapshotSamples());
2285 EXPECT_EQ(samples1->TotalCount() + 1, samples2->TotalCount());
2287 // kValidCookieLine creates a session cookie.
2288 ASSERT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
2290 scoped_ptr<base::HistogramSamples> samples3(
2291 expired_histogram->SnapshotSamples());
2292 EXPECT_EQ(samples2->TotalCount(), samples3->TotalCount());
2295 namespace {
2297 class MultiThreadedCookieMonsterTest : public CookieMonsterTest {
2298 public:
2299 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {}
2301 // Helper methods for calling the asynchronous CookieMonster methods
2302 // from a different thread.
2304 void GetAllCookiesTask(CookieMonster* cm,
2305 GetCookieListCallback* callback) {
2306 cm->GetAllCookiesAsync(
2307 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2310 void GetAllCookiesForURLTask(CookieMonster* cm,
2311 const GURL& url,
2312 GetCookieListCallback* callback) {
2313 cm->GetAllCookiesForURLAsync(
2314 url,
2315 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2318 void GetAllCookiesForURLWithOptionsTask(CookieMonster* cm,
2319 const GURL& url,
2320 const CookieOptions& options,
2321 GetCookieListCallback* callback) {
2322 cm->GetAllCookiesForURLWithOptionsAsync(
2323 url, options,
2324 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2327 void SetCookieWithDetailsTask(CookieMonster* cm, const GURL& url,
2328 BoolResultCookieCallback* callback) {
2329 // Define the parameters here instead of in the calling fucntion.
2330 // The maximum number of parameters for Bind function is 6.
2331 std::string name = "A";
2332 std::string value = "B";
2333 std::string domain = std::string();
2334 std::string path = "/foo";
2335 base::Time expiration_time = base::Time();
2336 bool secure = false;
2337 bool http_only = false;
2338 CookiePriority priority = COOKIE_PRIORITY_DEFAULT;
2339 cm->SetCookieWithDetailsAsync(
2340 url, name, value, domain, path, expiration_time, secure, http_only,
2341 priority,
2342 base::Bind(&BoolResultCookieCallback::Run, base::Unretained(callback)));
2345 void DeleteAllCreatedBetweenTask(CookieMonster* cm,
2346 const base::Time& delete_begin,
2347 const base::Time& delete_end,
2348 IntResultCookieCallback* callback) {
2349 cm->DeleteAllCreatedBetweenAsync(
2350 delete_begin, delete_end,
2351 base::Bind(&IntResultCookieCallback::Run,
2352 base::Unretained(callback)));
2355 void DeleteAllForHostTask(CookieMonster* cm,
2356 const GURL& url,
2357 IntResultCookieCallback* callback) {
2358 cm->DeleteAllForHostAsync(
2359 url,
2360 base::Bind(&IntResultCookieCallback::Run, base::Unretained(callback)));
2363 void DeleteCanonicalCookieTask(CookieMonster* cm,
2364 const CanonicalCookie& cookie,
2365 BoolResultCookieCallback* callback) {
2366 cm->DeleteCanonicalCookieAsync(
2367 cookie,
2368 base::Bind(&BoolResultCookieCallback::Run, base::Unretained(callback)));
2371 protected:
2372 void RunOnOtherThread(const base::Closure& task) {
2373 other_thread_.Start();
2374 other_thread_.message_loop()->PostTask(FROM_HERE, task);
2375 RunFor(kTimeout);
2376 other_thread_.Stop();
2379 Thread other_thread_;
2382 } // namespace
2384 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookies) {
2385 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2386 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2387 CookieList cookies = GetAllCookies(cm.get());
2388 CookieList::const_iterator it = cookies.begin();
2389 ASSERT_TRUE(it != cookies.end());
2390 EXPECT_EQ("www.google.izzle", it->Domain());
2391 EXPECT_EQ("A", it->Name());
2392 ASSERT_TRUE(++it == cookies.end());
2393 GetCookieListCallback callback(&other_thread_);
2394 base::Closure task =
2395 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesTask,
2396 base::Unretained(this),
2397 cm, &callback);
2398 RunOnOtherThread(task);
2399 EXPECT_TRUE(callback.did_run());
2400 it = callback.cookies().begin();
2401 ASSERT_TRUE(it != callback.cookies().end());
2402 EXPECT_EQ("www.google.izzle", it->Domain());
2403 EXPECT_EQ("A", it->Name());
2404 ASSERT_TRUE(++it == callback.cookies().end());
2407 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURL) {
2408 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2409 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2410 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
2411 CookieList::const_iterator it = cookies.begin();
2412 ASSERT_TRUE(it != cookies.end());
2413 EXPECT_EQ("www.google.izzle", it->Domain());
2414 EXPECT_EQ("A", it->Name());
2415 ASSERT_TRUE(++it == cookies.end());
2416 GetCookieListCallback callback(&other_thread_);
2417 base::Closure task =
2418 base::Bind(&net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask,
2419 base::Unretained(this),
2420 cm, url_google_, &callback);
2421 RunOnOtherThread(task);
2422 EXPECT_TRUE(callback.did_run());
2423 it = callback.cookies().begin();
2424 ASSERT_TRUE(it != callback.cookies().end());
2425 EXPECT_EQ("www.google.izzle", it->Domain());
2426 EXPECT_EQ("A", it->Name());
2427 ASSERT_TRUE(++it == callback.cookies().end());
2430 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURLWithOpt) {
2431 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2432 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2433 CookieOptions options;
2434 CookieList cookies =
2435 GetAllCookiesForURLWithOptions(cm.get(), url_google_, options);
2436 CookieList::const_iterator it = cookies.begin();
2437 ASSERT_TRUE(it != cookies.end());
2438 EXPECT_EQ("www.google.izzle", it->Domain());
2439 EXPECT_EQ("A", it->Name());
2440 ASSERT_TRUE(++it == cookies.end());
2441 GetCookieListCallback callback(&other_thread_);
2442 base::Closure task = base::Bind(
2443 &net::MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask,
2444 base::Unretained(this),
2445 cm, url_google_, options, &callback);
2446 RunOnOtherThread(task);
2447 EXPECT_TRUE(callback.did_run());
2448 it = callback.cookies().begin();
2449 ASSERT_TRUE(it != callback.cookies().end());
2450 EXPECT_EQ("www.google.izzle", it->Domain());
2451 EXPECT_EQ("A", it->Name());
2452 ASSERT_TRUE(++it == callback.cookies().end());
2455 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) {
2456 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2457 EXPECT_TRUE(SetCookieWithDetails(cm.get(),
2458 url_google_foo_,
2459 "A",
2460 "B",
2461 std::string(),
2462 "/foo",
2463 base::Time(),
2464 false,
2465 false,
2466 COOKIE_PRIORITY_DEFAULT));
2467 BoolResultCookieCallback callback(&other_thread_);
2468 base::Closure task = base::Bind(
2469 &net::MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask,
2470 base::Unretained(this),
2471 cm, url_google_foo_, &callback);
2472 RunOnOtherThread(task);
2473 EXPECT_TRUE(callback.did_run());
2474 EXPECT_TRUE(callback.result());
2477 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllCreatedBetween) {
2478 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2479 CookieOptions options;
2480 Time now = Time::Now();
2481 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2482 EXPECT_EQ(
2484 DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99), Time()));
2485 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2486 IntResultCookieCallback callback(&other_thread_);
2487 base::Closure task = base::Bind(
2488 &net::MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask,
2489 base::Unretained(this),
2490 cm, now - TimeDelta::FromDays(99),
2491 Time(), &callback);
2492 RunOnOtherThread(task);
2493 EXPECT_TRUE(callback.did_run());
2494 EXPECT_EQ(1, callback.result());
2497 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllForHost) {
2498 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2499 CookieOptions options;
2500 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2501 EXPECT_EQ(1, DeleteAllForHost(cm.get(), url_google_));
2502 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2503 IntResultCookieCallback callback(&other_thread_);
2504 base::Closure task = base::Bind(
2505 &net::MultiThreadedCookieMonsterTest::DeleteAllForHostTask,
2506 base::Unretained(this),
2507 cm, url_google_, &callback);
2508 RunOnOtherThread(task);
2509 EXPECT_TRUE(callback.did_run());
2510 EXPECT_EQ(1, callback.result());
2513 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) {
2514 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2515 CookieOptions options;
2516 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2517 CookieList cookies = GetAllCookies(cm.get());
2518 CookieList::iterator it = cookies.begin();
2519 EXPECT_TRUE(DeleteCanonicalCookie(cm.get(), *it));
2521 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2522 BoolResultCookieCallback callback(&other_thread_);
2523 cookies = GetAllCookies(cm.get());
2524 it = cookies.begin();
2525 base::Closure task = base::Bind(
2526 &net::MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask,
2527 base::Unretained(this),
2528 cm, *it, &callback);
2529 RunOnOtherThread(task);
2530 EXPECT_TRUE(callback.did_run());
2531 EXPECT_TRUE(callback.result());
2534 TEST_F(CookieMonsterTest, InvalidExpiryTime) {
2535 std::string cookie_line =
2536 std::string(kValidCookieLine) + "; expires=Blarg arg arg";
2537 scoped_ptr<CanonicalCookie> cookie(
2538 CanonicalCookie::Create(url_google_, cookie_line, Time::Now(),
2539 CookieOptions()));
2540 ASSERT_FALSE(cookie->IsPersistent());
2543 // Test that CookieMonster writes session cookies into the underlying
2544 // CookieStore if the "persist session cookies" option is on.
2545 TEST_F(CookieMonsterTest, PersistSessionCookies) {
2546 scoped_refptr<MockPersistentCookieStore> store(
2547 new MockPersistentCookieStore);
2548 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2549 cm->SetPersistSessionCookies(true);
2551 // All cookies set with SetCookie are session cookies.
2552 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2553 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
2555 // The cookie was written to the backing store.
2556 EXPECT_EQ(1u, store->commands().size());
2557 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
2558 EXPECT_EQ("A", store->commands()[0].cookie.Name());
2559 EXPECT_EQ("B", store->commands()[0].cookie.Value());
2561 // Modify the cookie.
2562 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=C"));
2563 EXPECT_EQ("A=C", GetCookies(cm.get(), url_google_));
2564 EXPECT_EQ(3u, store->commands().size());
2565 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2566 EXPECT_EQ("A", store->commands()[1].cookie.Name());
2567 EXPECT_EQ("B", store->commands()[1].cookie.Value());
2568 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
2569 EXPECT_EQ("A", store->commands()[2].cookie.Name());
2570 EXPECT_EQ("C", store->commands()[2].cookie.Value());
2572 // Delete the cookie.
2573 DeleteCookie(cm.get(), url_google_, "A");
2574 EXPECT_EQ("", GetCookies(cm.get(), url_google_));
2575 EXPECT_EQ(4u, store->commands().size());
2576 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
2577 EXPECT_EQ("A", store->commands()[3].cookie.Name());
2578 EXPECT_EQ("C", store->commands()[3].cookie.Value());
2581 // Test the commands sent to the persistent cookie store.
2582 TEST_F(CookieMonsterTest, PersisentCookieStorageTest) {
2583 scoped_refptr<MockPersistentCookieStore> store(
2584 new MockPersistentCookieStore);
2585 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2587 // Add a cookie.
2588 EXPECT_TRUE(SetCookie(
2589 cm.get(), url_google_, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2590 this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
2591 ASSERT_EQ(1u, store->commands().size());
2592 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
2593 // Remove it.
2594 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B; max-age=0"));
2595 this->MatchCookieLines(std::string(), GetCookies(cm.get(), url_google_));
2596 ASSERT_EQ(2u, store->commands().size());
2597 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2599 // Add a cookie.
2600 EXPECT_TRUE(SetCookie(
2601 cm.get(), url_google_, "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2602 this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
2603 ASSERT_EQ(3u, store->commands().size());
2604 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
2605 // Overwrite it.
2606 EXPECT_TRUE(SetCookie(
2607 cm.get(), url_google_, "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
2608 this->MatchCookieLines("A=Foo", GetCookies(cm.get(), url_google_));
2609 ASSERT_EQ(5u, store->commands().size());
2610 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
2611 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type);
2613 // Create some non-persistent cookies and check that they don't go to the
2614 // persistent storage.
2615 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=Bar"));
2616 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm.get(), url_google_));
2617 EXPECT_EQ(5u, store->commands().size());
2620 } // namespace net