Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / cookies / cookie_monster_unittest.cc
blobc4df76558d7ccde4f6d40add0a4cbfca65bdbc51
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/location.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/histogram.h"
18 #include "base/metrics/histogram_samples.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_piece.h"
22 #include "base/strings/string_split.h"
23 #include "base/strings/string_tokenizer.h"
24 #include "base/strings/stringprintf.h"
25 #include "base/test/histogram_tester.h"
26 #include "base/thread_task_runner_handle.h"
27 #include "base/threading/thread.h"
28 #include "base/time/time.h"
29 #include "net/cookies/canonical_cookie.h"
30 #include "net/cookies/cookie_constants.h"
31 #include "net/cookies/cookie_monster.h"
32 #include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
33 #include "net/cookies/cookie_util.h"
34 #include "net/cookies/parsed_cookie.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37 #include "url/gurl.h"
39 namespace net {
41 using base::Time;
42 using base::TimeDelta;
44 namespace {
46 // TODO(erikwright): Replace the pre-existing MockPersistentCookieStore (and
47 // brethren) with this one, and remove the 'New' prefix.
48 class NewMockPersistentCookieStore
49 : public CookieMonster::PersistentCookieStore {
50 public:
51 MOCK_METHOD1(Load, void(const LoadedCallback& loaded_callback));
52 MOCK_METHOD2(LoadCookiesForKey,
53 void(const std::string& key,
54 const LoadedCallback& loaded_callback));
55 MOCK_METHOD1(AddCookie, void(const CanonicalCookie& cc));
56 MOCK_METHOD1(UpdateCookieAccessTime, void(const CanonicalCookie& cc));
57 MOCK_METHOD1(DeleteCookie, void(const CanonicalCookie& cc));
58 virtual void Flush(const base::Closure& callback) {
59 if (!callback.is_null())
60 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
62 MOCK_METHOD0(SetForceKeepSessionState, void());
64 private:
65 virtual ~NewMockPersistentCookieStore() {}
68 const char kTopLevelDomainPlus1[] = "http://www.harvard.edu";
69 const char kTopLevelDomainPlus2[] = "http://www.math.harvard.edu";
70 const char kTopLevelDomainPlus2Secure[] = "https://www.math.harvard.edu";
71 const char kTopLevelDomainPlus3[] = "http://www.bourbaki.math.harvard.edu";
72 const char kOtherDomain[] = "http://www.mit.edu";
73 const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle";
75 class GetCookieListCallback : public CookieCallback {
76 public:
77 GetCookieListCallback() {}
78 explicit GetCookieListCallback(Thread* run_in_thread)
79 : CookieCallback(run_in_thread) {}
81 void Run(const CookieList& cookies) {
82 cookies_ = cookies;
83 CallbackEpilogue();
86 const CookieList& cookies() { return cookies_; }
88 private:
89 CookieList cookies_;
92 struct CookieMonsterTestTraits {
93 static scoped_refptr<CookieStore> Create() {
94 return new CookieMonster(NULL, NULL);
97 static const bool is_cookie_monster = true;
98 static const bool supports_http_only = true;
99 static const bool supports_non_dotted_domains = true;
100 static const bool preserves_trailing_dots = true;
101 static const bool filters_schemes = true;
102 static const bool has_path_prefix_bug = false;
103 static const int creation_time_granularity_in_ms = 0;
106 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster,
107 CookieStoreTest,
108 CookieMonsterTestTraits);
110 INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster,
111 MultiThreadedCookieStoreTest,
112 CookieMonsterTestTraits);
114 class CookieMonsterTest : public CookieStoreTest<CookieMonsterTestTraits> {
115 protected:
116 CookieList GetAllCookies(CookieMonster* cm) {
117 DCHECK(cm);
118 GetCookieListCallback callback;
119 cm->GetAllCookiesAsync(
120 base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
121 RunFor(kTimeout);
122 EXPECT_TRUE(callback.did_run());
123 return callback.cookies();
126 CookieList GetAllCookiesForURL(CookieMonster* cm, const GURL& url) {
127 DCHECK(cm);
128 GetCookieListCallback callback;
129 cm->GetAllCookiesForURLAsync(url, base::Bind(&GetCookieListCallback::Run,
130 base::Unretained(&callback)));
131 RunFor(kTimeout);
132 EXPECT_TRUE(callback.did_run());
133 return callback.cookies();
136 CookieList GetAllCookiesForURLWithOptions(CookieMonster* cm,
137 const GURL& url,
138 const CookieOptions& options) {
139 DCHECK(cm);
140 GetCookieListCallback callback;
141 cm->GetAllCookiesForURLWithOptionsAsync(
142 url, options,
143 base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
144 RunFor(kTimeout);
145 EXPECT_TRUE(callback.did_run());
146 return callback.cookies();
149 bool SetCookieWithDetails(CookieMonster* cm,
150 const GURL& url,
151 const std::string& name,
152 const std::string& value,
153 const std::string& domain,
154 const std::string& path,
155 const base::Time& expiration_time,
156 bool secure,
157 bool http_only,
158 bool first_party_only,
159 CookiePriority priority) {
160 DCHECK(cm);
161 ResultSavingCookieCallback<bool> callback;
162 cm->SetCookieWithDetailsAsync(
163 url, name, value, domain, path, expiration_time, secure, http_only,
164 first_party_only, priority,
165 base::Bind(&ResultSavingCookieCallback<bool>::Run,
166 base::Unretained(&callback)));
167 RunFor(kTimeout);
168 EXPECT_TRUE(callback.did_run());
169 return callback.result();
172 bool SetAllCookies(CookieMonster* cm, const CookieList& list) {
173 DCHECK(cm);
174 ResultSavingCookieCallback<bool> callback;
175 cm->SetAllCookiesAsync(list,
176 base::Bind(&ResultSavingCookieCallback<bool>::Run,
177 base::Unretained(&callback)));
178 RunFor(kTimeout);
179 EXPECT_TRUE(callback.did_run());
180 return callback.result();
183 int DeleteAll(CookieMonster* cm) {
184 DCHECK(cm);
185 ResultSavingCookieCallback<int> callback;
186 cm->DeleteAllAsync(base::Bind(&ResultSavingCookieCallback<int>::Run,
187 base::Unretained(&callback)));
188 RunFor(kTimeout);
189 EXPECT_TRUE(callback.did_run());
190 return callback.result();
193 int DeleteAllCreatedBetween(CookieMonster* cm,
194 const base::Time& delete_begin,
195 const base::Time& delete_end) {
196 DCHECK(cm);
197 ResultSavingCookieCallback<int> callback;
198 cm->DeleteAllCreatedBetweenAsync(
199 delete_begin, delete_end,
200 base::Bind(&ResultSavingCookieCallback<int>::Run,
201 base::Unretained(&callback)));
202 RunFor(kTimeout);
203 EXPECT_TRUE(callback.did_run());
204 return callback.result();
207 int DeleteAllCreatedBetweenForHost(CookieMonster* cm,
208 const base::Time delete_begin,
209 const base::Time delete_end,
210 const GURL& url) {
211 DCHECK(cm);
212 ResultSavingCookieCallback<int> callback;
213 cm->DeleteAllCreatedBetweenForHostAsync(
214 delete_begin, delete_end, url,
215 base::Bind(&ResultSavingCookieCallback<int>::Run,
216 base::Unretained(&callback)));
217 RunFor(kTimeout);
218 EXPECT_TRUE(callback.did_run());
219 return callback.result();
222 int DeleteAllForHost(CookieMonster* cm, const GURL& url) {
223 DCHECK(cm);
224 ResultSavingCookieCallback<int> callback;
225 cm->DeleteAllForHostAsync(url,
226 base::Bind(&ResultSavingCookieCallback<int>::Run,
227 base::Unretained(&callback)));
228 RunFor(kTimeout);
229 EXPECT_TRUE(callback.did_run());
230 return callback.result();
233 bool DeleteCanonicalCookie(CookieMonster* cm, const CanonicalCookie& cookie) {
234 DCHECK(cm);
235 ResultSavingCookieCallback<bool> callback;
236 cm->DeleteCanonicalCookieAsync(
237 cookie, base::Bind(&ResultSavingCookieCallback<bool>::Run,
238 base::Unretained(&callback)));
239 RunFor(kTimeout);
240 EXPECT_TRUE(callback.did_run());
241 return callback.result();
244 // Helper for DeleteAllForHost test; repopulates CM with same layout
245 // each time.
246 void PopulateCmForDeleteAllForHost(scoped_refptr<CookieMonster> cm) {
247 GURL url_top_level_domain_plus_1(kTopLevelDomainPlus1);
248 GURL url_top_level_domain_plus_2(kTopLevelDomainPlus2);
249 GURL url_top_level_domain_plus_2_secure(kTopLevelDomainPlus2Secure);
250 GURL url_top_level_domain_plus_3(kTopLevelDomainPlus3);
251 GURL url_other(kOtherDomain);
253 DeleteAll(cm.get());
255 // Static population for probe:
256 // * Three levels of domain cookie (.b.a, .c.b.a, .d.c.b.a)
257 // * Three levels of host cookie (w.b.a, w.c.b.a, w.d.c.b.a)
258 // * http_only cookie (w.c.b.a)
259 // * first-party cookie (w.c.b.a)
260 // * Two secure cookies (.c.b.a, w.c.b.a)
261 // * Two domain path cookies (.c.b.a/dir1, .c.b.a/dir1/dir2)
262 // * Two host path cookies (w.c.b.a/dir1, w.c.b.a/dir1/dir2)
264 // Domain cookies
265 EXPECT_TRUE(this->SetCookieWithDetails(
266 cm.get(), url_top_level_domain_plus_1, "dom_1", "X", ".harvard.edu",
267 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
268 EXPECT_TRUE(this->SetCookieWithDetails(
269 cm.get(), url_top_level_domain_plus_2, "dom_2", "X",
270 ".math.harvard.edu", "/", base::Time(), false, false, false,
271 COOKIE_PRIORITY_DEFAULT));
272 EXPECT_TRUE(this->SetCookieWithDetails(
273 cm.get(), url_top_level_domain_plus_3, "dom_3", "X",
274 ".bourbaki.math.harvard.edu", "/", base::Time(), false, false, false,
275 COOKIE_PRIORITY_DEFAULT));
277 // Host cookies
278 EXPECT_TRUE(this->SetCookieWithDetails(
279 cm.get(), url_top_level_domain_plus_1, "host_1", "X", std::string(),
280 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
281 EXPECT_TRUE(this->SetCookieWithDetails(
282 cm.get(), url_top_level_domain_plus_2, "host_2", "X", std::string(),
283 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
284 EXPECT_TRUE(this->SetCookieWithDetails(
285 cm.get(), url_top_level_domain_plus_3, "host_3", "X", std::string(),
286 "/", base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
288 // http_only cookie
289 EXPECT_TRUE(this->SetCookieWithDetails(
290 cm.get(), url_top_level_domain_plus_2, "httpo_check", "x",
291 std::string(), "/", base::Time(), false, true, false,
292 COOKIE_PRIORITY_DEFAULT));
294 // first-party cookie
295 EXPECT_TRUE(this->SetCookieWithDetails(
296 cm.get(), url_top_level_domain_plus_2, "firstp_check", "x",
297 std::string(), "/", base::Time(), false, false, true,
298 COOKIE_PRIORITY_DEFAULT));
300 // Secure cookies
301 EXPECT_TRUE(this->SetCookieWithDetails(
302 cm.get(), url_top_level_domain_plus_2_secure, "sec_dom", "X",
303 ".math.harvard.edu", "/", base::Time(), true, false, false,
304 COOKIE_PRIORITY_DEFAULT));
305 EXPECT_TRUE(this->SetCookieWithDetails(
306 cm.get(), url_top_level_domain_plus_2_secure, "sec_host", "X",
307 std::string(), "/", base::Time(), true, false, false,
308 COOKIE_PRIORITY_DEFAULT));
310 // Domain path cookies
311 EXPECT_TRUE(this->SetCookieWithDetails(
312 cm.get(), url_top_level_domain_plus_2, "dom_path_1", "X",
313 ".math.harvard.edu", "/dir1", base::Time(), false, false, false,
314 COOKIE_PRIORITY_DEFAULT));
315 EXPECT_TRUE(this->SetCookieWithDetails(
316 cm.get(), url_top_level_domain_plus_2, "dom_path_2", "X",
317 ".math.harvard.edu", "/dir1/dir2", base::Time(), false, false, false,
318 COOKIE_PRIORITY_DEFAULT));
320 // Host path cookies
321 EXPECT_TRUE(this->SetCookieWithDetails(
322 cm.get(), url_top_level_domain_plus_2, "host_path_1", "X",
323 std::string(), "/dir1", base::Time(), false, false, false,
324 COOKIE_PRIORITY_DEFAULT));
325 EXPECT_TRUE(this->SetCookieWithDetails(
326 cm.get(), url_top_level_domain_plus_2, "host_path_2", "X",
327 std::string(), "/dir1/dir2", base::Time(), false, false, false,
328 COOKIE_PRIORITY_DEFAULT));
330 EXPECT_EQ(14U, this->GetAllCookies(cm.get()).size());
333 Time GetFirstCookieAccessDate(CookieMonster* cm) {
334 const CookieList all_cookies(this->GetAllCookies(cm));
335 return all_cookies.front().LastAccessDate();
338 bool FindAndDeleteCookie(CookieMonster* cm,
339 const std::string& domain,
340 const std::string& name) {
341 CookieList cookies = this->GetAllCookies(cm);
342 for (CookieList::iterator it = cookies.begin(); it != cookies.end(); ++it)
343 if (it->Domain() == domain && it->Name() == name)
344 return this->DeleteCanonicalCookie(cm, *it);
345 return false;
348 int CountInString(const std::string& str, char c) {
349 return std::count(str.begin(), str.end(), c);
352 void TestHostGarbageCollectHelper() {
353 int domain_max_cookies = CookieMonster::kDomainMaxCookies;
354 int domain_purge_cookies = CookieMonster::kDomainPurgeCookies;
355 const int more_than_enough_cookies =
356 (domain_max_cookies + domain_purge_cookies) * 2;
357 // Add a bunch of cookies on a single host, should purge them.
359 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
360 for (int i = 0; i < more_than_enough_cookies; ++i) {
361 std::string cookie = base::StringPrintf("a%03d=b", i);
362 EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie));
363 std::string cookies = this->GetCookies(cm.get(), url_google_);
364 // Make sure we find it in the cookies.
365 EXPECT_NE(cookies.find(cookie), std::string::npos);
366 // Count the number of cookies.
367 EXPECT_LE(CountInString(cookies, '='), domain_max_cookies);
371 // Add a bunch of cookies on multiple hosts within a single eTLD.
372 // Should keep at least kDomainMaxCookies - kDomainPurgeCookies
373 // between them. We shouldn't go above kDomainMaxCookies for both together.
374 GURL url_google_specific(kUrlGoogleSpecific);
376 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
377 for (int i = 0; i < more_than_enough_cookies; ++i) {
378 std::string cookie_general = base::StringPrintf("a%03d=b", i);
379 EXPECT_TRUE(SetCookie(cm.get(), url_google_, cookie_general));
380 std::string cookie_specific = base::StringPrintf("c%03d=b", i);
381 EXPECT_TRUE(SetCookie(cm.get(), url_google_specific, cookie_specific));
382 std::string cookies_general = this->GetCookies(cm.get(), url_google_);
383 EXPECT_NE(cookies_general.find(cookie_general), std::string::npos);
384 std::string cookies_specific =
385 this->GetCookies(cm.get(), url_google_specific);
386 EXPECT_NE(cookies_specific.find(cookie_specific), std::string::npos);
387 EXPECT_LE((CountInString(cookies_general, '=') +
388 CountInString(cookies_specific, '=')),
389 domain_max_cookies);
391 // After all this, there should be at least
392 // kDomainMaxCookies - kDomainPurgeCookies for both URLs.
393 std::string cookies_general = this->GetCookies(cm.get(), url_google_);
394 std::string cookies_specific =
395 this->GetCookies(cm.get(), url_google_specific);
396 int total_cookies = (CountInString(cookies_general, '=') +
397 CountInString(cookies_specific, '='));
398 EXPECT_GE(total_cookies, domain_max_cookies - domain_purge_cookies);
399 EXPECT_LE(total_cookies, domain_max_cookies);
403 CookiePriority CharToPriority(char ch) {
404 switch (ch) {
405 case 'L':
406 return COOKIE_PRIORITY_LOW;
407 case 'M':
408 return COOKIE_PRIORITY_MEDIUM;
409 case 'H':
410 return COOKIE_PRIORITY_HIGH;
412 NOTREACHED();
413 return COOKIE_PRIORITY_DEFAULT;
416 // Instantiates a CookieMonster, adds multiple cookies (to url_google_) with
417 // priorities specified by |coded_priority_str|, and tests priority-aware
418 // domain cookie eviction.
419 // |coded_priority_str| specifies a run-length-encoded string of priorities.
420 // Example: "2M 3L M 4H" means "MMLLLMHHHH", and speicifies sequential (i.e.,
421 // from least- to most-recently accessed) insertion of 2 medium-priority
422 // cookies, 3 low-priority cookies, 1 medium-priority cookie, and 4
423 // high-priority cookies.
424 // Within each priority, only the least-accessed cookies should be evicted.
425 // Thus, to describe expected suriving cookies, it suffices to specify the
426 // expected population of surviving cookies per priority, i.e.,
427 // |expected_low_count|, |expected_medium_count|, and |expected_high_count|.
428 void TestPriorityCookieCase(CookieMonster* cm,
429 const std::string& coded_priority_str,
430 size_t expected_low_count,
431 size_t expected_medium_count,
432 size_t expected_high_count) {
433 DeleteAll(cm);
434 int next_cookie_id = 0;
435 std::vector<CookiePriority> priority_list;
436 std::vector<int> id_list[3]; // Indexed by CookiePriority.
438 // Parse |coded_priority_str| and add cookies.
439 for (const std::string& token :
440 base::SplitString(coded_priority_str, " ", base::TRIM_WHITESPACE,
441 base::SPLIT_WANT_ALL)) {
442 DCHECK(!token.empty());
443 // Take last character as priority.
444 CookiePriority priority = CharToPriority(token[token.length() - 1]);
445 std::string priority_str = CookiePriorityToString(priority);
446 // The rest of the string (possibly empty) specifies repetition.
447 int rep = 1;
448 if (!token.empty()) {
449 bool result = base::StringToInt(
450 base::StringPiece(token.begin(), token.end() - 1), &rep);
451 DCHECK(result);
453 for (; rep > 0; --rep, ++next_cookie_id) {
454 std::string cookie = base::StringPrintf(
455 "a%d=b;priority=%s", next_cookie_id, priority_str.c_str());
456 EXPECT_TRUE(SetCookie(cm, url_google_, cookie));
457 priority_list.push_back(priority);
458 id_list[priority].push_back(next_cookie_id);
462 int num_cookies = static_cast<int>(priority_list.size());
463 std::vector<int> surviving_id_list[3]; // Indexed by CookiePriority.
465 // Parse the list of cookies
466 std::string cookie_str = this->GetCookies(cm, url_google_);
467 for (const std::string& token : base::SplitString(
468 cookie_str, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
469 // Assuming *it is "a#=b", so extract and parse "#" portion.
470 int id = -1;
471 bool result = base::StringToInt(
472 base::StringPiece(token.begin() + 1, token.end() - 2), &id);
473 DCHECK(result);
474 DCHECK_GE(id, 0);
475 DCHECK_LT(id, num_cookies);
476 surviving_id_list[priority_list[id]].push_back(id);
479 // Validate each priority.
480 size_t expected_count[3] = {
481 expected_low_count, expected_medium_count, expected_high_count};
482 for (int i = 0; i < 3; ++i) {
483 DCHECK_LE(surviving_id_list[i].size(), id_list[i].size());
484 EXPECT_EQ(expected_count[i], surviving_id_list[i].size());
485 // Verify that the remaining cookies are the most recent among those
486 // with the same priorities.
487 if (expected_count[i] == surviving_id_list[i].size()) {
488 std::sort(surviving_id_list[i].begin(), surviving_id_list[i].end());
489 EXPECT_TRUE(std::equal(surviving_id_list[i].begin(),
490 surviving_id_list[i].end(),
491 id_list[i].end() - expected_count[i]));
496 void TestPriorityAwareGarbageCollectHelper() {
497 // Hard-coding limits in the test, but use DCHECK_EQ to enforce constraint.
498 DCHECK_EQ(180U, CookieMonster::kDomainMaxCookies);
499 DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
500 CookieMonster::kDomainPurgeCookies);
501 DCHECK_EQ(30U, CookieMonster::kDomainCookiesQuotaLow);
502 DCHECK_EQ(50U, CookieMonster::kDomainCookiesQuotaMedium);
503 DCHECK_EQ(70U, CookieMonster::kDomainCookiesQuotaHigh);
505 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
507 // Each test case adds 181 cookies, so 31 cookies are evicted.
508 // Cookie same priority, repeated for each priority.
509 TestPriorityCookieCase(cm.get(), "181L", 150U, 0U, 0U);
510 TestPriorityCookieCase(cm.get(), "181M", 0U, 150U, 0U);
511 TestPriorityCookieCase(cm.get(), "181H", 0U, 0U, 150U);
513 // Pairwise scenarios.
514 // Round 1 => none; round2 => 31M; round 3 => none.
515 TestPriorityCookieCase(cm.get(), "10H 171M", 0U, 140U, 10U);
516 // Round 1 => 10L; round2 => 21M; round 3 => none.
517 TestPriorityCookieCase(cm.get(), "141M 40L", 30U, 120U, 0U);
518 // Round 1 => none; round2 => none; round 3 => 31H.
519 TestPriorityCookieCase(cm.get(), "101H 80M", 0U, 80U, 70U);
521 // For {low, medium} priorities right on quota, different orders.
522 // Round 1 => 1L; round 2 => none, round3 => 30L.
523 TestPriorityCookieCase(cm.get(), "31L 50M 100H", 0U, 50U, 100U);
524 // Round 1 => none; round 2 => 1M, round3 => 30M.
525 TestPriorityCookieCase(cm.get(), "51M 100H 30L", 30U, 20U, 100U);
526 // Round 1 => none; round 2 => none; round3 => 31H.
527 TestPriorityCookieCase(cm.get(), "101H 50M 30L", 30U, 50U, 70U);
529 // Round 1 => 10L; round 2 => 10M; round3 => 11H.
530 TestPriorityCookieCase(cm.get(), "81H 60M 40L", 30U, 50U, 70U);
532 // More complex scenarios.
533 // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
534 TestPriorityCookieCase(cm.get(), "21H 60M 40L 60H", 30U, 50U, 70U);
535 // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
536 TestPriorityCookieCase(cm.get(), "11H 10M 20L 110M 20L 10H", 20U, 109U,
537 21U);
538 // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
539 TestPriorityCookieCase(cm.get(), "11L 10M 140H 10M 10L", 10U, 10U, 130U);
540 // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
541 TestPriorityCookieCase(cm.get(), "11M 10H 10L 60M 90H", 0U, 60U, 90U);
542 // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
543 TestPriorityCookieCase(cm.get(), "11M 10H 10L 90M 60H", 0U, 80U, 70U);
546 // Function for creating a CM with a number of cookies in it,
547 // no store (and hence no ability to affect access time).
548 CookieMonster* CreateMonsterForGC(int num_cookies) {
549 CookieMonster* cm(new CookieMonster(NULL, NULL));
550 for (int i = 0; i < num_cookies; i++) {
551 SetCookie(cm, GURL(base::StringPrintf("http://h%05d.izzle", i)), "a=1");
553 return cm;
556 bool IsCookieInList(const CanonicalCookie& cookie, const CookieList& list) {
557 for (CookieList::const_iterator it = list.begin(); it != list.end(); ++it) {
558 if (it->Source() == cookie.Source() && it->Name() == cookie.Name() &&
559 it->Value() == cookie.Value() && it->Domain() == cookie.Domain() &&
560 it->Path() == cookie.Path() &&
561 it->CreationDate() == cookie.CreationDate() &&
562 it->ExpiryDate() == cookie.ExpiryDate() &&
563 it->LastAccessDate() == cookie.LastAccessDate() &&
564 it->IsSecure() == cookie.IsSecure() &&
565 it->IsHttpOnly() == cookie.IsHttpOnly() &&
566 it->Priority() == cookie.Priority()) {
567 return true;
571 return false;
575 // TODO(erikwright): Replace the other callbacks and synchronous helper methods
576 // in this test suite with these Mocks.
577 template <typename T, typename C>
578 class MockCookieCallback {
579 public:
580 C AsCallback() {
581 return base::Bind(&T::Invoke, base::Unretained(static_cast<T*>(this)));
585 class MockGetCookiesCallback
586 : public MockCookieCallback<MockGetCookiesCallback,
587 CookieStore::GetCookiesCallback> {
588 public:
589 MOCK_METHOD1(Invoke, void(const std::string& cookies));
592 class MockSetCookiesCallback
593 : public MockCookieCallback<MockSetCookiesCallback,
594 CookieStore::SetCookiesCallback> {
595 public:
596 MOCK_METHOD1(Invoke, void(bool success));
599 class MockClosure : public MockCookieCallback<MockClosure, base::Closure> {
600 public:
601 MOCK_METHOD0(Invoke, void(void));
604 class MockGetCookieListCallback
605 : public MockCookieCallback<MockGetCookieListCallback,
606 CookieMonster::GetCookieListCallback> {
607 public:
608 MOCK_METHOD1(Invoke, void(const CookieList& cookies));
611 class MockDeleteCallback
612 : public MockCookieCallback<MockDeleteCallback,
613 CookieMonster::DeleteCallback> {
614 public:
615 MOCK_METHOD1(Invoke, void(int num_deleted));
618 class MockDeleteCookieCallback
619 : public MockCookieCallback<MockDeleteCookieCallback,
620 CookieMonster::DeleteCookieCallback> {
621 public:
622 MOCK_METHOD1(Invoke, void(bool success));
625 struct CookiesInputInfo {
626 const GURL url;
627 const std::string name;
628 const std::string value;
629 const std::string domain;
630 const std::string path;
631 const base::Time expiration_time;
632 bool secure;
633 bool http_only;
634 bool first_party_only;
635 CookiePriority priority;
638 ACTION(QuitCurrentMessageLoop) {
639 base::ThreadTaskRunnerHandle::Get()->PostTask(
640 FROM_HERE, base::MessageLoop::QuitClosure());
643 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
644 // rename these, removing the 'Action' suffix.
645 ACTION_P4(DeleteCookieAction, cookie_monster, url, name, callback) {
646 cookie_monster->DeleteCookieAsync(url, name, callback->AsCallback());
648 ACTION_P3(GetCookiesAction, cookie_monster, url, callback) {
649 cookie_monster->GetCookiesWithOptionsAsync(url, CookieOptions(),
650 callback->AsCallback());
652 ACTION_P4(SetCookieAction, cookie_monster, url, cookie_line, callback) {
653 cookie_monster->SetCookieWithOptionsAsync(url, cookie_line, CookieOptions(),
654 callback->AsCallback());
656 ACTION_P3(SetAllCookiesAction, cookie_monster, list, callback) {
657 cookie_monster->SetAllCookiesAsync(list, callback->AsCallback());
659 ACTION_P4(DeleteAllCreatedBetweenAction,
660 cookie_monster,
661 delete_begin,
662 delete_end,
663 callback) {
664 cookie_monster->DeleteAllCreatedBetweenAsync(delete_begin, delete_end,
665 callback->AsCallback());
667 ACTION_P3(SetCookieWithDetailsAction, cookie_monster, cc, callback) {
668 cookie_monster->SetCookieWithDetailsAsync(
669 cc.url, cc.name, cc.value, cc.domain, cc.path, cc.expiration_time,
670 cc.secure, cc.http_only, cc.first_party_only, cc.priority,
671 callback->AsCallback());
674 ACTION_P2(GetAllCookiesAction, cookie_monster, callback) {
675 cookie_monster->GetAllCookiesAsync(callback->AsCallback());
678 ACTION_P3(DeleteAllForHostAction, cookie_monster, url, callback) {
679 cookie_monster->DeleteAllForHostAsync(url, callback->AsCallback());
682 ACTION_P3(DeleteCanonicalCookieAction, cookie_monster, cookie, callback) {
683 cookie_monster->DeleteCanonicalCookieAsync(cookie, callback->AsCallback());
686 ACTION_P2(DeleteAllAction, cookie_monster, callback) {
687 cookie_monster->DeleteAllAsync(callback->AsCallback());
690 ACTION_P3(GetAllCookiesForUrlWithOptionsAction, cookie_monster, url, callback) {
691 cookie_monster->GetAllCookiesForURLWithOptionsAsync(url, CookieOptions(),
692 callback->AsCallback());
695 ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) {
696 cookie_monster->GetAllCookiesForURLAsync(url, callback->AsCallback());
699 ACTION_P(PushCallbackAction, callback_vector) {
700 callback_vector->push(arg1);
703 ACTION_P2(DeleteSessionCookiesAction, cookie_monster, callback) {
704 cookie_monster->DeleteSessionCookiesAsync(callback->AsCallback());
707 } // namespace
709 // This test suite verifies the task deferral behaviour of the CookieMonster.
710 // Specifically, for each asynchronous method, verify that:
711 // 1. invoking it on an uninitialized cookie store causes the store to begin
712 // chain-loading its backing data or loading data for a specific domain key
713 // (eTLD+1).
714 // 2. The initial invocation does not complete until the loading completes.
715 // 3. Invocations after the loading has completed complete immediately.
716 class DeferredCookieTaskTest : public CookieMonsterTest {
717 protected:
718 DeferredCookieTaskTest() {
719 persistent_store_ = new NewMockPersistentCookieStore();
720 cookie_monster_ = new CookieMonster(persistent_store_.get(), NULL);
723 // Defines a cookie to be returned from PersistentCookieStore::Load
724 void DeclareLoadedCookie(const std::string& key,
725 const std::string& cookie_line,
726 const base::Time& creation_time) {
727 AddCookieToList(key, cookie_line, creation_time, &loaded_cookies_);
730 // Runs the message loop, waiting until PersistentCookieStore::Load is called.
731 // Call CompleteLoadingAndWait to cause the load to complete.
732 void WaitForLoadCall() {
733 RunFor(kTimeout);
735 // Verify that PeristentStore::Load was called.
736 testing::Mock::VerifyAndClear(persistent_store_.get());
739 // Invokes the PersistentCookieStore::LoadCookiesForKey completion callbacks
740 // and PersistentCookieStore::Load completion callback and waits
741 // until the message loop is quit.
742 void CompleteLoadingAndWait() {
743 while (!loaded_for_key_callbacks_.empty()) {
744 loaded_for_key_callbacks_.front().Run(loaded_cookies_);
745 loaded_cookies_.clear();
746 loaded_for_key_callbacks_.pop();
749 loaded_callback_.Run(loaded_cookies_);
750 RunFor(kTimeout);
753 // Performs the provided action, expecting it to cause a call to
754 // PersistentCookieStore::Load. Call WaitForLoadCall to verify the load call
755 // is received.
756 void BeginWith(testing::Action<void(void)> action) {
757 EXPECT_CALL(*this, Begin()).WillOnce(action);
758 ExpectLoadCall();
759 Begin();
762 void BeginWithForDomainKey(std::string key,
763 testing::Action<void(void)> action) {
764 EXPECT_CALL(*this, Begin()).WillOnce(action);
765 ExpectLoadCall();
766 ExpectLoadForKeyCall(key, false);
767 Begin();
770 // Declares an expectation that PersistentCookieStore::Load will be called,
771 // saving the provided callback and sending a quit to the message loop.
772 void ExpectLoadCall() {
773 EXPECT_CALL(*persistent_store_.get(), Load(testing::_))
774 .WillOnce(testing::DoAll(testing::SaveArg<0>(&loaded_callback_),
775 QuitCurrentMessageLoop()));
778 // Declares an expectation that PersistentCookieStore::LoadCookiesForKey
779 // will be called, saving the provided callback and sending a quit to the
780 // message loop.
781 void ExpectLoadForKeyCall(const std::string& key, bool quit_queue) {
782 if (quit_queue)
783 EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_))
784 .WillOnce(
785 testing::DoAll(PushCallbackAction(&loaded_for_key_callbacks_),
786 QuitCurrentMessageLoop()));
787 else
788 EXPECT_CALL(*persistent_store_.get(), LoadCookiesForKey(key, testing::_))
789 .WillOnce(PushCallbackAction(&loaded_for_key_callbacks_));
792 // Invokes the initial action.
793 MOCK_METHOD0(Begin, void(void));
795 // Returns the CookieMonster instance under test.
796 CookieMonster& cookie_monster() { return *cookie_monster_.get(); }
798 private:
799 // Declares that mock expectations in this test suite are strictly ordered.
800 testing::InSequence in_sequence_;
801 // Holds cookies to be returned from PersistentCookieStore::Load or
802 // PersistentCookieStore::LoadCookiesForKey.
803 std::vector<CanonicalCookie*> loaded_cookies_;
804 // Stores the callback passed from the CookieMonster to the
805 // PersistentCookieStore::Load
806 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_;
807 // Stores the callback passed from the CookieMonster to the
808 // PersistentCookieStore::LoadCookiesForKey
809 std::queue<CookieMonster::PersistentCookieStore::LoadedCallback>
810 loaded_for_key_callbacks_;
812 // Stores the CookieMonster under test.
813 scoped_refptr<CookieMonster> cookie_monster_;
814 // Stores the mock PersistentCookieStore.
815 scoped_refptr<NewMockPersistentCookieStore> persistent_store_;
818 TEST_F(DeferredCookieTaskTest, DeferredGetCookies) {
819 DeclareLoadedCookie("www.google.izzle",
820 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
821 Time::Now() + TimeDelta::FromDays(3));
823 MockGetCookiesCallback get_cookies_callback;
825 BeginWithForDomainKey(
826 "google.izzle",
827 GetCookiesAction(&cookie_monster(), url_google_, &get_cookies_callback));
829 WaitForLoadCall();
831 EXPECT_CALL(get_cookies_callback, Invoke("X=1"))
832 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_,
833 &get_cookies_callback));
834 EXPECT_CALL(get_cookies_callback, Invoke("X=1"))
835 .WillOnce(QuitCurrentMessageLoop());
837 CompleteLoadingAndWait();
840 TEST_F(DeferredCookieTaskTest, DeferredSetCookie) {
841 MockSetCookiesCallback set_cookies_callback;
843 BeginWithForDomainKey("google.izzle",
844 SetCookieAction(&cookie_monster(), url_google_, "A=B",
845 &set_cookies_callback));
847 WaitForLoadCall();
849 EXPECT_CALL(set_cookies_callback, Invoke(true))
850 .WillOnce(SetCookieAction(&cookie_monster(), url_google_, "X=Y",
851 &set_cookies_callback));
852 EXPECT_CALL(set_cookies_callback, Invoke(true))
853 .WillOnce(QuitCurrentMessageLoop());
855 CompleteLoadingAndWait();
858 TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) {
859 MockSetCookiesCallback set_cookies_callback;
860 CookieList list;
861 list.push_back(CanonicalCookie(url_google_, "A", "B", "google.izzle", "/",
862 base::Time::Now(), base::Time(), base::Time(),
863 false, true, false, COOKIE_PRIORITY_DEFAULT));
864 list.push_back(CanonicalCookie(url_google_, "C", "D", "google.izzle", "/",
865 base::Time::Now(), base::Time(), base::Time(),
866 false, true, false, COOKIE_PRIORITY_DEFAULT));
868 BeginWith(
869 SetAllCookiesAction(&cookie_monster(), list, &set_cookies_callback));
871 WaitForLoadCall();
873 EXPECT_CALL(set_cookies_callback, Invoke(true))
874 .WillOnce(
875 SetAllCookiesAction(&cookie_monster(), list, &set_cookies_callback));
876 EXPECT_CALL(set_cookies_callback, Invoke(true))
877 .WillOnce(QuitCurrentMessageLoop());
879 CompleteLoadingAndWait();
882 TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) {
883 MockClosure delete_cookie_callback;
885 BeginWithForDomainKey("google.izzle",
886 DeleteCookieAction(&cookie_monster(), url_google_, "A",
887 &delete_cookie_callback));
889 WaitForLoadCall();
891 EXPECT_CALL(delete_cookie_callback, Invoke())
892 .WillOnce(DeleteCookieAction(&cookie_monster(), url_google_, "X",
893 &delete_cookie_callback));
894 EXPECT_CALL(delete_cookie_callback, Invoke())
895 .WillOnce(QuitCurrentMessageLoop());
897 CompleteLoadingAndWait();
900 TEST_F(DeferredCookieTaskTest, DeferredSetCookieWithDetails) {
901 MockSetCookiesCallback set_cookies_callback;
903 CookiesInputInfo cookie_info = {url_google_foo_,
904 "A",
905 "B",
906 std::string(),
907 "/foo",
908 base::Time(),
909 false,
910 false,
911 false,
912 COOKIE_PRIORITY_DEFAULT};
913 BeginWithForDomainKey(
914 "google.izzle", SetCookieWithDetailsAction(&cookie_monster(), cookie_info,
915 &set_cookies_callback));
917 WaitForLoadCall();
919 CookiesInputInfo cookie_info_exp = {url_google_foo_,
920 "A",
921 "B",
922 std::string(),
923 "/foo",
924 base::Time(),
925 false,
926 false,
927 false,
928 COOKIE_PRIORITY_DEFAULT};
929 EXPECT_CALL(set_cookies_callback, Invoke(true))
930 .WillOnce(SetCookieWithDetailsAction(&cookie_monster(), cookie_info_exp,
931 &set_cookies_callback));
932 EXPECT_CALL(set_cookies_callback, Invoke(true))
933 .WillOnce(QuitCurrentMessageLoop());
935 CompleteLoadingAndWait();
938 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) {
939 DeclareLoadedCookie("www.google.izzle",
940 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
941 Time::Now() + TimeDelta::FromDays(3));
943 MockGetCookieListCallback get_cookie_list_callback;
945 BeginWith(GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback));
947 WaitForLoadCall();
949 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
950 .WillOnce(
951 GetAllCookiesAction(&cookie_monster(), &get_cookie_list_callback));
952 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
953 .WillOnce(QuitCurrentMessageLoop());
955 CompleteLoadingAndWait();
958 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlCookies) {
959 DeclareLoadedCookie("www.google.izzle",
960 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
961 Time::Now() + TimeDelta::FromDays(3));
963 MockGetCookieListCallback get_cookie_list_callback;
965 BeginWithForDomainKey(
966 "google.izzle", GetAllCookiesForUrlAction(&cookie_monster(), url_google_,
967 &get_cookie_list_callback));
969 WaitForLoadCall();
971 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
972 .WillOnce(GetAllCookiesForUrlAction(&cookie_monster(), url_google_,
973 &get_cookie_list_callback));
974 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
975 .WillOnce(QuitCurrentMessageLoop());
977 CompleteLoadingAndWait();
980 TEST_F(DeferredCookieTaskTest, DeferredGetAllForUrlWithOptionsCookies) {
981 DeclareLoadedCookie("www.google.izzle",
982 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
983 Time::Now() + TimeDelta::FromDays(3));
985 MockGetCookieListCallback get_cookie_list_callback;
987 BeginWithForDomainKey("google.izzle", GetAllCookiesForUrlWithOptionsAction(
988 &cookie_monster(), url_google_,
989 &get_cookie_list_callback));
991 WaitForLoadCall();
993 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
994 .WillOnce(GetAllCookiesForUrlWithOptionsAction(
995 &cookie_monster(), url_google_, &get_cookie_list_callback));
996 EXPECT_CALL(get_cookie_list_callback, Invoke(testing::_))
997 .WillOnce(QuitCurrentMessageLoop());
999 CompleteLoadingAndWait();
1002 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCookies) {
1003 MockDeleteCallback delete_callback;
1005 BeginWith(DeleteAllAction(&cookie_monster(), &delete_callback));
1007 WaitForLoadCall();
1009 EXPECT_CALL(delete_callback, Invoke(false))
1010 .WillOnce(DeleteAllAction(&cookie_monster(), &delete_callback));
1011 EXPECT_CALL(delete_callback, Invoke(false))
1012 .WillOnce(QuitCurrentMessageLoop());
1014 CompleteLoadingAndWait();
1017 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllCreatedBetweenCookies) {
1018 MockDeleteCallback delete_callback;
1020 BeginWith(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
1021 base::Time::Now(), &delete_callback));
1023 WaitForLoadCall();
1025 EXPECT_CALL(delete_callback, Invoke(false))
1026 .WillOnce(DeleteAllCreatedBetweenAction(&cookie_monster(), base::Time(),
1027 base::Time::Now(),
1028 &delete_callback));
1029 EXPECT_CALL(delete_callback, Invoke(false))
1030 .WillOnce(QuitCurrentMessageLoop());
1032 CompleteLoadingAndWait();
1035 TEST_F(DeferredCookieTaskTest, DeferredDeleteAllForHostCookies) {
1036 MockDeleteCallback delete_callback;
1038 BeginWithForDomainKey(
1039 "google.izzle",
1040 DeleteAllForHostAction(&cookie_monster(), url_google_, &delete_callback));
1042 WaitForLoadCall();
1044 EXPECT_CALL(delete_callback, Invoke(false))
1045 .WillOnce(DeleteAllForHostAction(&cookie_monster(), url_google_,
1046 &delete_callback));
1047 EXPECT_CALL(delete_callback, Invoke(false))
1048 .WillOnce(QuitCurrentMessageLoop());
1050 CompleteLoadingAndWait();
1053 TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) {
1054 std::vector<CanonicalCookie*> cookies;
1055 CanonicalCookie cookie =
1056 BuildCanonicalCookie("www.google.com", "X=1; path=/", base::Time::Now());
1058 MockDeleteCookieCallback delete_cookie_callback;
1060 BeginWith(DeleteCanonicalCookieAction(&cookie_monster(), cookie,
1061 &delete_cookie_callback));
1063 WaitForLoadCall();
1065 EXPECT_CALL(delete_cookie_callback, Invoke(false))
1066 .WillOnce(DeleteCanonicalCookieAction(&cookie_monster(), cookie,
1067 &delete_cookie_callback));
1068 EXPECT_CALL(delete_cookie_callback, Invoke(false))
1069 .WillOnce(QuitCurrentMessageLoop());
1071 CompleteLoadingAndWait();
1074 TEST_F(DeferredCookieTaskTest, DeferredDeleteSessionCookies) {
1075 MockDeleteCallback delete_callback;
1077 BeginWith(DeleteSessionCookiesAction(&cookie_monster(), &delete_callback));
1079 WaitForLoadCall();
1081 EXPECT_CALL(delete_callback, Invoke(false))
1082 .WillOnce(
1083 DeleteSessionCookiesAction(&cookie_monster(), &delete_callback));
1084 EXPECT_CALL(delete_callback, Invoke(false))
1085 .WillOnce(QuitCurrentMessageLoop());
1087 CompleteLoadingAndWait();
1090 // Verify that a series of queued tasks are executed in order upon loading of
1091 // the backing store and that new tasks received while the queued tasks are
1092 // being dispatched go to the end of the queue.
1093 TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {
1094 DeclareLoadedCookie("www.google.izzle",
1095 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1096 Time::Now() + TimeDelta::FromDays(3));
1098 MockGetCookiesCallback get_cookies_callback;
1099 MockSetCookiesCallback set_cookies_callback;
1100 MockGetCookiesCallback get_cookies_callback_deferred;
1102 EXPECT_CALL(*this, Begin())
1103 .WillOnce(testing::DoAll(GetCookiesAction(&cookie_monster(), url_google_,
1104 &get_cookies_callback),
1105 SetCookieAction(&cookie_monster(), url_google_,
1106 "A=B", &set_cookies_callback)));
1107 ExpectLoadCall();
1108 ExpectLoadForKeyCall("google.izzle", false);
1109 Begin();
1111 WaitForLoadCall();
1112 EXPECT_CALL(get_cookies_callback, Invoke("X=1"))
1113 .WillOnce(GetCookiesAction(&cookie_monster(), url_google_,
1114 &get_cookies_callback_deferred));
1115 EXPECT_CALL(set_cookies_callback, Invoke(true));
1116 EXPECT_CALL(get_cookies_callback_deferred, Invoke("A=B; X=1"))
1117 .WillOnce(QuitCurrentMessageLoop());
1119 CompleteLoadingAndWait();
1122 TEST_F(CookieMonsterTest, TestCookieDeleteAll) {
1123 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
1124 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1125 CookieOptions options;
1126 options.set_include_httponly();
1128 EXPECT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
1129 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1131 EXPECT_TRUE(
1132 SetCookieWithOptions(cm.get(), url_google_, "C=D; httponly", options));
1133 EXPECT_EQ("A=B; C=D", GetCookiesWithOptions(cm.get(), url_google_, options));
1135 EXPECT_EQ(2, DeleteAll(cm.get()));
1136 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
1137 EXPECT_EQ(0u, store->commands().size());
1139 // Create a persistent cookie.
1140 EXPECT_TRUE(SetCookie(
1141 cm.get(), url_google_,
1142 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
1143 ASSERT_EQ(1u, store->commands().size());
1144 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1146 EXPECT_EQ(1, DeleteAll(cm.get())); // sync_to_store = true.
1147 ASSERT_EQ(2u, store->commands().size());
1148 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1150 EXPECT_EQ("", GetCookiesWithOptions(cm.get(), url_google_, options));
1153 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) {
1154 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1155 Time now = Time::Now();
1157 // Nothing has been added so nothing should be deleted.
1158 EXPECT_EQ(0, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99),
1159 Time()));
1161 // Create 3 cookies with creation date of today, yesterday and the day before.
1162 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-0=Now", now));
1163 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-1=Yesterday",
1164 now - TimeDelta::FromDays(1)));
1165 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-2=DayBefore",
1166 now - TimeDelta::FromDays(2)));
1167 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-3=ThreeDays",
1168 now - TimeDelta::FromDays(3)));
1169 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "T-7=LastWeek",
1170 now - TimeDelta::FromDays(7)));
1172 // Try to delete threedays and the daybefore.
1173 EXPECT_EQ(2, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(3),
1174 now - TimeDelta::FromDays(1)));
1176 // Try to delete yesterday, also make sure that delete_end is not
1177 // inclusive.
1178 EXPECT_EQ(
1179 1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(2), now));
1181 // Make sure the delete_begin is inclusive.
1182 EXPECT_EQ(
1183 1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(7), now));
1185 // Delete the last (now) item.
1186 EXPECT_EQ(1, DeleteAllCreatedBetween(cm.get(), Time(), Time()));
1188 // Really make sure everything is gone.
1189 EXPECT_EQ(0, DeleteAll(cm.get()));
1192 static const int kAccessDelayMs = kLastAccessThresholdMilliseconds + 20;
1194 TEST_F(CookieMonsterTest, TestLastAccess) {
1195 scoped_refptr<CookieMonster> cm(
1196 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1198 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1199 const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
1201 // Reading the cookie again immediately shouldn't update the access date,
1202 // since we're inside the threshold.
1203 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1204 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1206 // Reading after a short wait should update the access date.
1207 base::PlatformThread::Sleep(
1208 base::TimeDelta::FromMilliseconds(kAccessDelayMs));
1209 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
1210 EXPECT_FALSE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1213 TEST_F(CookieMonsterTest, TestHostGarbageCollection) {
1214 TestHostGarbageCollectHelper();
1217 TEST_F(CookieMonsterTest, TestPriorityAwareGarbageCollection) {
1218 TestPriorityAwareGarbageCollectHelper();
1221 TEST_F(CookieMonsterTest, TestDeleteSingleCookie) {
1222 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1224 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1225 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
1226 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
1227 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
1229 EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
1230 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1232 EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
1233 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1236 TEST_F(CookieMonsterTest, SetCookieableSchemes) {
1237 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1238 scoped_refptr<CookieMonster> cm_foo(new CookieMonster(NULL, NULL));
1240 // Only cm_foo should allow foo:// cookies.
1241 const char* const kSchemes[] = {"foo"};
1242 cm_foo->SetCookieableSchemes(kSchemes, 1);
1244 GURL foo_url("foo://host/path");
1245 GURL http_url("http://host/path");
1247 EXPECT_TRUE(SetCookie(cm.get(), http_url, "x=1"));
1248 EXPECT_FALSE(SetCookie(cm.get(), foo_url, "x=1"));
1249 EXPECT_TRUE(SetCookie(cm_foo.get(), foo_url, "x=1"));
1250 EXPECT_FALSE(SetCookie(cm_foo.get(), http_url, "x=1"));
1253 TEST_F(CookieMonsterTest, GetAllCookiesForURL) {
1254 scoped_refptr<CookieMonster> cm(
1255 new CookieMonster(NULL, NULL, kLastAccessThresholdMilliseconds));
1257 // Create an httponly cookie.
1258 CookieOptions options;
1259 options.set_include_httponly();
1261 EXPECT_TRUE(
1262 SetCookieWithOptions(cm.get(), url_google_, "A=B; httponly", options));
1263 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
1264 "C=D; domain=.google.izzle", options));
1265 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_secure_,
1266 "E=F; domain=.google.izzle; secure",
1267 options));
1269 const Time last_access_date(GetFirstCookieAccessDate(cm.get()));
1271 base::PlatformThread::Sleep(
1272 base::TimeDelta::FromMilliseconds(kAccessDelayMs));
1274 // Check cookies for url.
1275 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
1276 CookieList::iterator it = cookies.begin();
1278 ASSERT_TRUE(it != cookies.end());
1279 EXPECT_EQ("www.google.izzle", it->Domain());
1280 EXPECT_EQ("A", it->Name());
1282 ASSERT_TRUE(++it != cookies.end());
1283 EXPECT_EQ(".google.izzle", it->Domain());
1284 EXPECT_EQ("C", it->Name());
1286 ASSERT_TRUE(++it == cookies.end());
1288 // Check cookies for url excluding http-only cookies.
1289 cookies =
1290 GetAllCookiesForURLWithOptions(cm.get(), url_google_, CookieOptions());
1291 it = cookies.begin();
1293 ASSERT_TRUE(it != cookies.end());
1294 EXPECT_EQ(".google.izzle", it->Domain());
1295 EXPECT_EQ("C", it->Name());
1297 ASSERT_TRUE(++it == cookies.end());
1299 // Test secure cookies.
1300 cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
1301 it = cookies.begin();
1303 ASSERT_TRUE(it != cookies.end());
1304 EXPECT_EQ("www.google.izzle", it->Domain());
1305 EXPECT_EQ("A", it->Name());
1307 ASSERT_TRUE(++it != cookies.end());
1308 EXPECT_EQ(".google.izzle", it->Domain());
1309 EXPECT_EQ("C", it->Name());
1311 ASSERT_TRUE(++it != cookies.end());
1312 EXPECT_EQ(".google.izzle", it->Domain());
1313 EXPECT_EQ("E", it->Name());
1315 ASSERT_TRUE(++it == cookies.end());
1317 // Reading after a short wait should not update the access date.
1318 EXPECT_TRUE(last_access_date == GetFirstCookieAccessDate(cm.get()));
1321 TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
1322 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1323 CookieOptions options;
1325 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_foo_, "A=B; path=/foo;",
1326 options));
1327 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_bar_, "C=D; path=/bar;",
1328 options));
1329 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "E=F;", options));
1331 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
1332 CookieList::iterator it = cookies.begin();
1334 ASSERT_TRUE(it != cookies.end());
1335 EXPECT_EQ("A", it->Name());
1336 EXPECT_EQ("/foo", it->Path());
1338 ASSERT_TRUE(++it != cookies.end());
1339 EXPECT_EQ("E", it->Name());
1340 EXPECT_EQ("/", it->Path());
1342 ASSERT_TRUE(++it == cookies.end());
1344 cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
1345 it = cookies.begin();
1347 ASSERT_TRUE(it != cookies.end());
1348 EXPECT_EQ("C", it->Name());
1349 EXPECT_EQ("/bar", it->Path());
1351 ASSERT_TRUE(++it != cookies.end());
1352 EXPECT_EQ("E", it->Name());
1353 EXPECT_EQ("/", it->Path());
1355 ASSERT_TRUE(++it == cookies.end());
1358 TEST_F(CookieMonsterTest, CookieSorting) {
1359 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1361 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B1; path=/"));
1362 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B2; path=/foo"));
1363 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/foo/bar"));
1364 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A1; path=/"));
1365 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A2; path=/foo"));
1366 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A3; path=/foo/bar"));
1368 // Re-set cookie which should not change sort order.
1369 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/foo/bar"));
1371 CookieList cookies = GetAllCookies(cm.get());
1372 ASSERT_EQ(6u, cookies.size());
1373 // According to RFC 6265 5.3 (11) re-setting this cookie should retain the
1374 // initial creation-time from above, and the sort order should not change.
1375 // Chrome's current implementation deviates from the spec so capturing this to
1376 // avoid any inadvertent changes to this behavior.
1377 EXPECT_EQ("A3", cookies[0].Value());
1378 EXPECT_EQ("B3", cookies[1].Value());
1379 EXPECT_EQ("B2", cookies[2].Value());
1380 EXPECT_EQ("A2", cookies[3].Value());
1381 EXPECT_EQ("B1", cookies[4].Value());
1382 EXPECT_EQ("A1", cookies[5].Value());
1385 TEST_F(CookieMonsterTest, DeleteCookieByName) {
1386 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1388 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A1; path=/"));
1389 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A2; path=/foo"));
1390 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=A3; path=/bar"));
1391 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B1; path=/"));
1392 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B2; path=/foo"));
1393 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=B3; path=/bar"));
1395 DeleteCookie(cm.get(), GURL(std::string(kUrlGoogle) + "/foo/bar"), "A");
1397 CookieList cookies = GetAllCookies(cm.get());
1398 size_t expected_size = 4;
1399 EXPECT_EQ(expected_size, cookies.size());
1400 for (CookieList::iterator it = cookies.begin(); it != cookies.end(); ++it) {
1401 EXPECT_NE("A1", it->Value());
1402 EXPECT_NE("A2", it->Value());
1406 TEST_F(CookieMonsterTest, ImportCookiesFromCookieMonster) {
1407 scoped_refptr<CookieMonster> cm_1(new CookieMonster(NULL, NULL));
1408 CookieOptions options;
1410 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_foo_,
1411 "A1=B; path=/foo;", options));
1412 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_bar_,
1413 "A2=D; path=/bar;", options));
1414 EXPECT_TRUE(SetCookieWithOptions(cm_1.get(), url_google_, "A3=F;", options));
1416 CookieList cookies_1 = GetAllCookies(cm_1.get());
1417 scoped_refptr<CookieMonster> cm_2(new CookieMonster(NULL, NULL));
1418 ASSERT_TRUE(cm_2->ImportCookies(cookies_1));
1419 CookieList cookies_2 = GetAllCookies(cm_2.get());
1421 size_t expected_size = 3;
1422 EXPECT_EQ(expected_size, cookies_2.size());
1424 CookieList::iterator it = cookies_2.begin();
1426 ASSERT_TRUE(it != cookies_2.end());
1427 EXPECT_EQ("A1", it->Name());
1428 EXPECT_EQ("/foo", it->Path());
1430 ASSERT_TRUE(++it != cookies_2.end());
1431 EXPECT_EQ("A2", it->Name());
1432 EXPECT_EQ("/bar", it->Path());
1434 ASSERT_TRUE(++it != cookies_2.end());
1435 EXPECT_EQ("A3", it->Name());
1436 EXPECT_EQ("/", it->Path());
1439 // Tests importing from a persistent cookie store that contains duplicate
1440 // equivalent cookies. This situation should be handled by removing the
1441 // duplicate cookie (both from the in-memory cache, and from the backing store).
1443 // This is a regression test for: http://crbug.com/17855.
1444 TEST_F(CookieMonsterTest, DontImportDuplicateCookies) {
1445 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
1447 // We will fill some initial cookies into the PersistentCookieStore,
1448 // to simulate a database with 4 duplicates. Note that we need to
1449 // be careful not to have any duplicate creation times at all (as it's a
1450 // violation of a CookieMonster invariant) even if Time::Now() doesn't
1451 // move between calls.
1452 std::vector<CanonicalCookie*> initial_cookies;
1454 // Insert 4 cookies with name "X" on path "/", with varying creation
1455 // dates. We expect only the most recent one to be preserved following
1456 // the import.
1458 AddCookieToList("www.google.com",
1459 "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1460 Time::Now() + TimeDelta::FromDays(3), &initial_cookies);
1462 AddCookieToList("www.google.com",
1463 "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1464 Time::Now() + TimeDelta::FromDays(1), &initial_cookies);
1466 // ===> This one is the WINNER (biggest creation time). <====
1467 AddCookieToList("www.google.com",
1468 "X=3; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1469 Time::Now() + TimeDelta::FromDays(4), &initial_cookies);
1471 AddCookieToList("www.google.com",
1472 "X=4; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1473 Time::Now(), &initial_cookies);
1475 // Insert 2 cookies with name "X" on path "/2", with varying creation
1476 // dates. We expect only the most recent one to be preserved the import.
1478 // ===> This one is the WINNER (biggest creation time). <====
1479 AddCookieToList("www.google.com",
1480 "X=a1; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1481 Time::Now() + TimeDelta::FromDays(9), &initial_cookies);
1483 AddCookieToList("www.google.com",
1484 "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
1485 Time::Now() + TimeDelta::FromDays(2), &initial_cookies);
1487 // Insert 1 cookie with name "Y" on path "/".
1488 AddCookieToList("www.google.com",
1489 "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
1490 Time::Now() + TimeDelta::FromDays(10), &initial_cookies);
1492 // Inject our initial cookies into the mock PersistentCookieStore.
1493 store->SetLoadExpectation(true, initial_cookies);
1495 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1497 // Verify that duplicates were not imported for path "/".
1498 // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
1499 EXPECT_EQ("X=3; Y=a", GetCookies(cm.get(), GURL("http://www.google.com/")));
1501 // Verify that same-named cookie on a different path ("/x2") didn't get
1502 // messed up.
1503 EXPECT_EQ("X=a1; X=3; Y=a",
1504 GetCookies(cm.get(), GURL("http://www.google.com/2/x")));
1506 // Verify that the PersistentCookieStore was told to kill its 4 duplicates.
1507 ASSERT_EQ(4u, store->commands().size());
1508 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[0].type);
1509 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1510 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[2].type);
1511 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
1514 // Tests importing from a persistent cookie store that contains cookies
1515 // with duplicate creation times. This situation should be handled by
1516 // dropping the cookies before insertion/visibility to user.
1518 // This is a regression test for: http://crbug.com/43188.
1519 TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) {
1520 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
1522 Time now(Time::Now());
1523 Time earlier(now - TimeDelta::FromDays(1));
1525 // Insert 8 cookies, four with the current time as creation times, and
1526 // four with the earlier time as creation times. We should only get
1527 // two cookies remaining, but which two (other than that there should
1528 // be one from each set) will be random.
1529 std::vector<CanonicalCookie*> initial_cookies;
1530 AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies);
1531 AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies);
1532 AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies);
1533 AddCookieToList("www.google.com", "X=4; path=/", now, &initial_cookies);
1535 AddCookieToList("www.google.com", "Y=1; path=/", earlier, &initial_cookies);
1536 AddCookieToList("www.google.com", "Y=2; path=/", earlier, &initial_cookies);
1537 AddCookieToList("www.google.com", "Y=3; path=/", earlier, &initial_cookies);
1538 AddCookieToList("www.google.com", "Y=4; path=/", earlier, &initial_cookies);
1540 // Inject our initial cookies into the mock PersistentCookieStore.
1541 store->SetLoadExpectation(true, initial_cookies);
1543 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
1545 CookieList list(GetAllCookies(cm.get()));
1546 EXPECT_EQ(2U, list.size());
1547 // Confirm that we have one of each.
1548 std::string name1(list[0].Name());
1549 std::string name2(list[1].Name());
1550 EXPECT_TRUE(name1 == "X" || name2 == "X");
1551 EXPECT_TRUE(name1 == "Y" || name2 == "Y");
1552 EXPECT_NE(name1, name2);
1555 TEST_F(CookieMonsterTest, CookieMonsterDelegate) {
1556 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
1557 scoped_refptr<MockCookieMonsterDelegate> delegate(
1558 new MockCookieMonsterDelegate);
1559 scoped_refptr<CookieMonster> cm(
1560 new CookieMonster(store.get(), delegate.get()));
1562 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
1563 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "C=D"));
1564 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "E=F"));
1565 EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), url_google_));
1566 ASSERT_EQ(3u, delegate->changes().size());
1567 EXPECT_FALSE(delegate->changes()[0].second);
1568 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1569 EXPECT_EQ("A", delegate->changes()[0].first.Name());
1570 EXPECT_EQ("B", delegate->changes()[0].first.Value());
1571 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
1572 EXPECT_FALSE(delegate->changes()[1].second);
1573 EXPECT_EQ("C", delegate->changes()[1].first.Name());
1574 EXPECT_EQ("D", delegate->changes()[1].first.Value());
1575 EXPECT_EQ(url_google_.host(), delegate->changes()[2].first.Domain());
1576 EXPECT_FALSE(delegate->changes()[2].second);
1577 EXPECT_EQ("E", delegate->changes()[2].first.Name());
1578 EXPECT_EQ("F", delegate->changes()[2].first.Value());
1579 delegate->reset();
1581 EXPECT_TRUE(FindAndDeleteCookie(cm.get(), url_google_.host(), "C"));
1582 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1583 ASSERT_EQ(1u, delegate->changes().size());
1584 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1585 EXPECT_TRUE(delegate->changes()[0].second);
1586 EXPECT_EQ("C", delegate->changes()[0].first.Name());
1587 EXPECT_EQ("D", delegate->changes()[0].first.Value());
1588 delegate->reset();
1590 EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E"));
1591 EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), url_google_));
1592 EXPECT_EQ(0u, delegate->changes().size());
1594 // Insert a cookie "a" for path "/path1"
1595 EXPECT_TRUE(SetCookie(cm.get(), url_google_,
1596 "a=val1; path=/path1; "
1597 "expires=Mon, 18-Apr-22 22:50:13 GMT"));
1598 ASSERT_EQ(1u, store->commands().size());
1599 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
1600 ASSERT_EQ(1u, delegate->changes().size());
1601 EXPECT_FALSE(delegate->changes()[0].second);
1602 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1603 EXPECT_EQ("a", delegate->changes()[0].first.Name());
1604 EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1605 delegate->reset();
1607 // Insert a cookie "a" for path "/path1", that is httponly. This should
1608 // overwrite the non-http-only version.
1609 CookieOptions allow_httponly;
1610 allow_httponly.set_include_httponly();
1611 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
1612 "a=val2; path=/path1; httponly; "
1613 "expires=Mon, 18-Apr-22 22:50:14 GMT",
1614 allow_httponly));
1615 ASSERT_EQ(3u, store->commands().size());
1616 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
1617 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
1618 ASSERT_EQ(2u, delegate->changes().size());
1619 EXPECT_EQ(url_google_.host(), delegate->changes()[0].first.Domain());
1620 EXPECT_TRUE(delegate->changes()[0].second);
1621 EXPECT_EQ("a", delegate->changes()[0].first.Name());
1622 EXPECT_EQ("val1", delegate->changes()[0].first.Value());
1623 EXPECT_EQ(url_google_.host(), delegate->changes()[1].first.Domain());
1624 EXPECT_FALSE(delegate->changes()[1].second);
1625 EXPECT_EQ("a", delegate->changes()[1].first.Name());
1626 EXPECT_EQ("val2", delegate->changes()[1].first.Value());
1627 delegate->reset();
1630 TEST_F(CookieMonsterTest, SetCookieWithDetails) {
1631 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1633 EXPECT_TRUE(SetCookieWithDetails(cm.get(), url_google_foo_, "A", "B",
1634 std::string(), "/foo", base::Time(), false,
1635 false, false, COOKIE_PRIORITY_DEFAULT));
1636 EXPECT_TRUE(SetCookieWithDetails(cm.get(), url_google_bar_, "C", "D",
1637 "google.izzle", "/bar", base::Time(), false,
1638 true, false, COOKIE_PRIORITY_DEFAULT));
1639 EXPECT_TRUE(SetCookieWithDetails(
1640 cm.get(), url_google_, "E", "F", std::string(), std::string(),
1641 base::Time(), true, false, false, COOKIE_PRIORITY_DEFAULT));
1643 // Test that malformed attributes fail to set the cookie.
1644 EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, " A", "B",
1645 std::string(), "/foo", base::Time(), false,
1646 false, false, COOKIE_PRIORITY_DEFAULT));
1647 EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, "A;", "B",
1648 std::string(), "/foo", base::Time(), false,
1649 false, false, COOKIE_PRIORITY_DEFAULT));
1650 EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, "A=", "B",
1651 std::string(), "/foo", base::Time(), false,
1652 false, false, COOKIE_PRIORITY_DEFAULT));
1653 EXPECT_FALSE(SetCookieWithDetails(
1654 cm.get(), url_google_foo_, "A", "B", "google.ozzzzzzle", "foo",
1655 base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
1656 EXPECT_FALSE(SetCookieWithDetails(cm.get(), url_google_foo_, "A=", "B",
1657 std::string(), "foo", base::Time(), false,
1658 false, false, COOKIE_PRIORITY_DEFAULT));
1660 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_foo_);
1661 CookieList::iterator it = cookies.begin();
1663 ASSERT_TRUE(it != cookies.end());
1664 EXPECT_EQ("A", it->Name());
1665 EXPECT_EQ("B", it->Value());
1666 EXPECT_EQ("www.google.izzle", it->Domain());
1667 EXPECT_EQ("/foo", it->Path());
1668 EXPECT_FALSE(it->IsPersistent());
1669 EXPECT_FALSE(it->IsSecure());
1670 EXPECT_FALSE(it->IsHttpOnly());
1672 ASSERT_TRUE(++it == cookies.end());
1674 cookies = GetAllCookiesForURL(cm.get(), url_google_bar_);
1675 it = cookies.begin();
1677 ASSERT_TRUE(it != cookies.end());
1678 EXPECT_EQ("C", it->Name());
1679 EXPECT_EQ("D", it->Value());
1680 EXPECT_EQ(".google.izzle", it->Domain());
1681 EXPECT_EQ("/bar", it->Path());
1682 EXPECT_FALSE(it->IsSecure());
1683 EXPECT_TRUE(it->IsHttpOnly());
1685 ASSERT_TRUE(++it == cookies.end());
1687 cookies = GetAllCookiesForURL(cm.get(), url_google_secure_);
1688 it = cookies.begin();
1690 ASSERT_TRUE(it != cookies.end());
1691 EXPECT_EQ("E", it->Name());
1692 EXPECT_EQ("F", it->Value());
1693 EXPECT_EQ("/", it->Path());
1694 EXPECT_EQ("www.google.izzle", it->Domain());
1695 EXPECT_TRUE(it->IsSecure());
1696 EXPECT_FALSE(it->IsHttpOnly());
1698 ASSERT_TRUE(++it == cookies.end());
1701 TEST_F(CookieMonsterTest, DeleteAllForHost) {
1702 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1704 // Test probes:
1705 // * Non-secure URL, mid-level (http://w.c.b.a)
1706 // * Secure URL, mid-level (https://w.c.b.a)
1707 // * URL with path, mid-level (https:/w.c.b.a/dir1/xx)
1708 // All three tests should nuke only the midlevel host cookie,
1709 // the http_only cookie, the host secure cookie, and the two host
1710 // path cookies. http_only, secure, and paths are ignored by
1711 // this call, and domain cookies arent touched.
1712 PopulateCmForDeleteAllForHost(cm);
1713 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1714 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1715 EXPECT_EQ("dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1716 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1717 EXPECT_EQ("dom_1=X; host_1=X",
1718 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1719 EXPECT_EQ(
1720 "dom_path_2=X; host_path_2=X; dom_path_1=X; host_path_1=X; "
1721 "dom_1=X; dom_2=X; host_2=X; sec_dom=X; sec_host=X",
1722 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure +
1723 std::string("/dir1/dir2/xxx"))));
1725 EXPECT_EQ(6, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2)));
1726 EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1728 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1729 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1730 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1731 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1732 EXPECT_EQ("dom_1=X; host_1=X",
1733 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1734 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1735 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure +
1736 std::string("/dir1/dir2/xxx"))));
1738 PopulateCmForDeleteAllForHost(cm);
1739 EXPECT_EQ(6, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1740 EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1742 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1743 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1744 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1745 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1746 EXPECT_EQ("dom_1=X; host_1=X",
1747 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1748 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1749 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure +
1750 std::string("/dir1/dir2/xxx"))));
1752 PopulateCmForDeleteAllForHost(cm);
1753 EXPECT_EQ(6, DeleteAllForHost(cm.get(), GURL(kTopLevelDomainPlus2Secure +
1754 std::string("/dir1/xxx"))));
1755 EXPECT_EQ(8U, GetAllCookies(cm.get()).size());
1757 EXPECT_EQ("dom_1=X; dom_2=X; dom_3=X; host_3=X",
1758 GetCookies(cm.get(), GURL(kTopLevelDomainPlus3)));
1759 EXPECT_EQ("dom_1=X; dom_2=X; sec_dom=X",
1760 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure)));
1761 EXPECT_EQ("dom_1=X; host_1=X",
1762 GetCookies(cm.get(), GURL(kTopLevelDomainPlus1)));
1763 EXPECT_EQ("dom_path_2=X; dom_path_1=X; dom_1=X; dom_2=X; sec_dom=X",
1764 GetCookies(cm.get(), GURL(kTopLevelDomainPlus2Secure +
1765 std::string("/dir1/dir2/xxx"))));
1768 TEST_F(CookieMonsterTest, UniqueCreationTime) {
1769 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1770 CookieOptions options;
1772 // Add in three cookies through every public interface to the
1773 // CookieMonster and confirm that none of them have duplicate
1774 // creation times.
1776 // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
1777 // are not included as they aren't going to be public for very much
1778 // longer.
1780 // SetCookie, SetCookieWithOptions, SetCookieWithDetails
1782 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "SetCookie1=A"));
1783 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "SetCookie2=A"));
1784 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "SetCookie3=A"));
1786 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
1787 "setCookieWithOptions1=A", options));
1788 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
1789 "setCookieWithOptions2=A", options));
1790 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_,
1791 "setCookieWithOptions3=A", options));
1793 EXPECT_TRUE(SetCookieWithDetails(
1794 cm.get(), url_google_, "setCookieWithDetails1", "A", ".google.izzle", "/",
1795 Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
1796 EXPECT_TRUE(SetCookieWithDetails(
1797 cm.get(), url_google_, "setCookieWithDetails2", "A", ".google.izzle", "/",
1798 Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
1799 EXPECT_TRUE(SetCookieWithDetails(
1800 cm.get(), url_google_, "setCookieWithDetails3", "A", ".google.izzle", "/",
1801 Time(), false, false, false, COOKIE_PRIORITY_DEFAULT));
1803 // Now we check
1804 CookieList cookie_list(GetAllCookies(cm.get()));
1805 EXPECT_EQ(9u, cookie_list.size());
1806 typedef std::map<int64, CanonicalCookie> TimeCookieMap;
1807 TimeCookieMap check_map;
1808 for (CookieList::const_iterator it = cookie_list.begin();
1809 it != cookie_list.end(); it++) {
1810 const int64 creation_date = it->CreationDate().ToInternalValue();
1811 TimeCookieMap::const_iterator existing_cookie_it(
1812 check_map.find(creation_date));
1813 EXPECT_TRUE(existing_cookie_it == check_map.end())
1814 << "Cookie " << it->Name() << " has same creation date ("
1815 << it->CreationDate().ToInternalValue()
1816 << ") as previously entered cookie "
1817 << existing_cookie_it->second.Name();
1819 if (existing_cookie_it == check_map.end()) {
1820 check_map.insert(
1821 TimeCookieMap::value_type(it->CreationDate().ToInternalValue(), *it));
1826 // Mainly a test of GetEffectiveDomain, or more specifically, of the
1827 // expected behavior of GetEffectiveDomain within the CookieMonster.
1828 TEST_F(CookieMonsterTest, GetKey) {
1829 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1831 // This test is really only interesting if GetKey() actually does something.
1832 EXPECT_EQ("google.com", cm->GetKey("www.google.com"));
1833 EXPECT_EQ("google.izzie", cm->GetKey("www.google.izzie"));
1834 EXPECT_EQ("google.izzie", cm->GetKey(".google.izzie"));
1835 EXPECT_EQ("bbc.co.uk", cm->GetKey("bbc.co.uk"));
1836 EXPECT_EQ("bbc.co.uk", cm->GetKey("a.b.c.d.bbc.co.uk"));
1837 EXPECT_EQ("apple.com", cm->GetKey("a.b.c.d.apple.com"));
1838 EXPECT_EQ("apple.izzie", cm->GetKey("a.b.c.d.apple.izzie"));
1840 // Cases where the effective domain is null, so we use the host
1841 // as the key.
1842 EXPECT_EQ("co.uk", cm->GetKey("co.uk"));
1843 const std::string extension_name("iehocdgbbocmkdidlbnnfbmbinnahbae");
1844 EXPECT_EQ(extension_name, cm->GetKey(extension_name));
1845 EXPECT_EQ("com", cm->GetKey("com"));
1846 EXPECT_EQ("hostalias", cm->GetKey("hostalias"));
1847 EXPECT_EQ("localhost", cm->GetKey("localhost"));
1850 // Test that cookies transfer from/to the backing store correctly.
1851 TEST_F(CookieMonsterTest, BackingStoreCommunication) {
1852 // Store details for cookies transforming through the backing store interface.
1854 base::Time current(base::Time::Now());
1855 scoped_refptr<MockSimplePersistentCookieStore> store(
1856 new MockSimplePersistentCookieStore);
1857 base::Time new_access_time;
1858 base::Time expires(base::Time::Now() + base::TimeDelta::FromSeconds(100));
1860 const CookiesInputInfo input_info[] = {
1861 {GURL("http://a.b.google.com"),
1862 "a",
1863 "1",
1865 "/path/to/cookie",
1866 expires,
1867 false,
1868 false,
1869 false,
1870 COOKIE_PRIORITY_DEFAULT},
1871 {GURL("https://www.google.com"),
1872 "b",
1873 "2",
1874 ".google.com",
1875 "/path/from/cookie",
1876 expires + TimeDelta::FromSeconds(10),
1877 true,
1878 true,
1879 false,
1880 COOKIE_PRIORITY_DEFAULT},
1881 {GURL("https://google.com"),
1882 "c",
1883 "3",
1885 "/another/path/to/cookie",
1886 base::Time::Now() + base::TimeDelta::FromSeconds(100),
1887 true,
1888 false,
1889 true,
1890 COOKIE_PRIORITY_DEFAULT}};
1891 const int INPUT_DELETE = 1;
1893 // Create new cookies and flush them to the store.
1895 scoped_refptr<CookieMonster> cmout(new CookieMonster(store.get(), NULL));
1896 for (const CookiesInputInfo* p = input_info;
1897 p < &input_info[arraysize(input_info)]; p++) {
1898 EXPECT_TRUE(SetCookieWithDetails(cmout.get(), p->url, p->name, p->value,
1899 p->domain, p->path, p->expiration_time,
1900 p->secure, p->http_only,
1901 p->first_party_only, p->priority));
1903 GURL del_url(input_info[INPUT_DELETE]
1904 .url.Resolve(input_info[INPUT_DELETE].path)
1905 .spec());
1906 DeleteCookie(cmout.get(), del_url, input_info[INPUT_DELETE].name);
1909 // Create a new cookie monster and make sure that everything is correct
1911 scoped_refptr<CookieMonster> cmin(new CookieMonster(store.get(), NULL));
1912 CookieList cookies(GetAllCookies(cmin.get()));
1913 ASSERT_EQ(2u, cookies.size());
1914 // Ordering is path length, then creation time. So second cookie
1915 // will come first, and we need to swap them.
1916 std::swap(cookies[0], cookies[1]);
1917 for (int output_index = 0; output_index < 2; output_index++) {
1918 int input_index = output_index * 2;
1919 const CookiesInputInfo* input = &input_info[input_index];
1920 const CanonicalCookie* output = &cookies[output_index];
1922 EXPECT_EQ(input->name, output->Name());
1923 EXPECT_EQ(input->value, output->Value());
1924 EXPECT_EQ(input->url.host(), output->Domain());
1925 EXPECT_EQ(input->path, output->Path());
1926 EXPECT_LE(current.ToInternalValue(),
1927 output->CreationDate().ToInternalValue());
1928 EXPECT_EQ(input->secure, output->IsSecure());
1929 EXPECT_EQ(input->http_only, output->IsHttpOnly());
1930 EXPECT_EQ(input->first_party_only, output->IsFirstPartyOnly());
1931 EXPECT_TRUE(output->IsPersistent());
1932 EXPECT_EQ(input->expiration_time.ToInternalValue(),
1933 output->ExpiryDate().ToInternalValue());
1938 TEST_F(CookieMonsterTest, CookieListOrdering) {
1939 // Put a random set of cookies into a monster and make sure
1940 // they're returned in the right order.
1941 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
1942 EXPECT_TRUE(
1943 SetCookie(cm.get(), GURL("http://d.c.b.a.google.com/aa/x.html"), "c=1"));
1944 EXPECT_TRUE(SetCookie(cm.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1945 "d=1; domain=b.a.google.com"));
1946 EXPECT_TRUE(SetCookie(cm.get(), GURL("http://b.a.google.com/aa/bb/cc/x.html"),
1947 "a=4; domain=b.a.google.com"));
1948 EXPECT_TRUE(SetCookie(cm.get(),
1949 GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
1950 "e=1; domain=c.b.a.google.com"));
1951 EXPECT_TRUE(SetCookie(cm.get(),
1952 GURL("http://d.c.b.a.google.com/aa/bb/x.html"), "b=1"));
1953 EXPECT_TRUE(SetCookie(cm.get(), GURL("http://news.bbc.co.uk/midpath/x.html"),
1954 "g=10"));
1956 unsigned int i = 0;
1957 CookieList cookies(GetAllCookiesForURL(
1958 cm.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
1959 ASSERT_EQ(5u, cookies.size());
1960 EXPECT_EQ("d", cookies[i++].Name());
1961 EXPECT_EQ("a", cookies[i++].Name());
1962 EXPECT_EQ("e", cookies[i++].Name());
1963 EXPECT_EQ("b", cookies[i++].Name());
1964 EXPECT_EQ("c", cookies[i++].Name());
1968 unsigned int i = 0;
1969 CookieList cookies(GetAllCookies(cm.get()));
1970 ASSERT_EQ(6u, cookies.size());
1971 EXPECT_EQ("d", cookies[i++].Name());
1972 EXPECT_EQ("a", cookies[i++].Name());
1973 EXPECT_EQ("e", cookies[i++].Name());
1974 EXPECT_EQ("g", cookies[i++].Name());
1975 EXPECT_EQ("b", cookies[i++].Name());
1976 EXPECT_EQ("c", cookies[i++].Name());
1980 // This test and CookieMonstertest.TestGCTimes (in cookie_monster_perftest.cc)
1981 // are somewhat complementary twins. This test is probing for whether
1982 // garbage collection always happens when it should (i.e. that we actually
1983 // get rid of cookies when we should). The perftest is probing for
1984 // whether garbage collection happens when it shouldn't. See comments
1985 // before that test for more details.
1987 // Disabled on Windows, see crbug.com/126095
1988 #if defined(OS_WIN)
1989 #define MAYBE_GarbageCollectionTriggers DISABLED_GarbageCollectionTriggers
1990 #else
1991 #define MAYBE_GarbageCollectionTriggers GarbageCollectionTriggers
1992 #endif
1994 TEST_F(CookieMonsterTest, MAYBE_GarbageCollectionTriggers) {
1995 // First we check to make sure that a whole lot of recent cookies
1996 // doesn't get rid of anything after garbage collection is checked for.
1998 scoped_refptr<CookieMonster> cm(
1999 CreateMonsterForGC(CookieMonster::kMaxCookies * 2));
2000 EXPECT_EQ(CookieMonster::kMaxCookies * 2, GetAllCookies(cm.get()).size());
2001 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
2002 EXPECT_EQ(CookieMonster::kMaxCookies * 2 + 1,
2003 GetAllCookies(cm.get()).size());
2006 // Now we explore a series of relationships between cookie last access
2007 // time and size of store to make sure we only get rid of cookies when
2008 // we really should.
2009 const struct TestCase {
2010 size_t num_cookies;
2011 size_t num_old_cookies;
2012 size_t expected_initial_cookies;
2013 // Indexed by ExpiryAndKeyScheme
2014 size_t expected_cookies_after_set;
2015 } test_cases[] = {
2016 {// A whole lot of recent cookies; gc shouldn't happen.
2017 CookieMonster::kMaxCookies * 2,
2019 CookieMonster::kMaxCookies * 2,
2020 CookieMonster::kMaxCookies * 2 + 1},
2021 {// Some old cookies, but still overflowing max.
2022 CookieMonster::kMaxCookies * 2,
2023 CookieMonster::kMaxCookies / 2,
2024 CookieMonster::kMaxCookies * 2,
2025 CookieMonster::kMaxCookies * 2 - CookieMonster::kMaxCookies / 2 + 1},
2026 {// Old cookies enough to bring us right down to our purge line.
2027 CookieMonster::kMaxCookies * 2,
2028 CookieMonster::kMaxCookies + CookieMonster::kPurgeCookies + 1,
2029 CookieMonster::kMaxCookies * 2,
2030 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies},
2031 {// Old cookies enough to bring below our purge line (which we
2032 // shouldn't do).
2033 CookieMonster::kMaxCookies * 2,
2034 CookieMonster::kMaxCookies * 3 / 2,
2035 CookieMonster::kMaxCookies * 2,
2036 CookieMonster::kMaxCookies - CookieMonster::kPurgeCookies}};
2038 for (int ci = 0; ci < static_cast<int>(arraysize(test_cases)); ++ci) {
2039 const TestCase* test_case = &test_cases[ci];
2040 scoped_refptr<CookieMonster> cm(CreateMonsterFromStoreForGC(
2041 test_case->num_cookies, test_case->num_old_cookies,
2042 CookieMonster::kSafeFromGlobalPurgeDays * 2));
2043 EXPECT_EQ(test_case->expected_initial_cookies,
2044 GetAllCookies(cm.get()).size())
2045 << "For test case " << ci;
2046 // Will trigger GC
2047 SetCookie(cm.get(), GURL("http://newdomain.com"), "b=2");
2048 EXPECT_EQ(test_case->expected_cookies_after_set,
2049 GetAllCookies(cm.get()).size())
2050 << "For test case " << ci;
2054 // This test checks that keep expired cookies flag is working.
2055 TEST_F(CookieMonsterTest, KeepExpiredCookies) {
2056 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2057 cm->SetKeepExpiredCookies();
2058 CookieOptions options;
2060 // Set a persistent cookie.
2061 ASSERT_TRUE(SetCookieWithOptions(
2062 cm.get(), url_google_,
2063 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-22 22:50:13 GMT",
2064 options));
2066 // Get the canonical cookie.
2067 CookieList cookie_list = GetAllCookies(cm.get());
2068 ASSERT_EQ(1U, cookie_list.size());
2070 // Use a past expiry date to delete the cookie.
2071 ASSERT_TRUE(SetCookieWithOptions(
2072 cm.get(), url_google_,
2073 std::string(kValidCookieLine) + "; expires=Mon, 18-Apr-1977 22:50:13 GMT",
2074 options));
2076 // Check that the cookie with the past expiry date is still there.
2077 // GetAllCookies() also triggers garbage collection.
2078 cookie_list = GetAllCookies(cm.get());
2079 ASSERT_EQ(1U, cookie_list.size());
2080 ASSERT_TRUE(cookie_list[0].IsExpired(Time::Now()));
2083 namespace {
2085 // Mock PersistentCookieStore that keeps track of the number of Flush() calls.
2086 class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
2087 public:
2088 FlushablePersistentStore() : flush_count_(0) {}
2090 void Load(const LoadedCallback& loaded_callback) override {
2091 std::vector<CanonicalCookie*> out_cookies;
2092 base::ThreadTaskRunnerHandle::Get()->PostTask(
2093 FROM_HERE,
2094 base::Bind(&LoadedCallbackTask::Run,
2095 new LoadedCallbackTask(loaded_callback, out_cookies)));
2098 void LoadCookiesForKey(const std::string& key,
2099 const LoadedCallback& loaded_callback) override {
2100 Load(loaded_callback);
2103 void AddCookie(const CanonicalCookie&) override {}
2104 void UpdateCookieAccessTime(const CanonicalCookie&) override {}
2105 void DeleteCookie(const CanonicalCookie&) override {}
2106 void SetForceKeepSessionState() override {}
2108 void Flush(const base::Closure& callback) override {
2109 ++flush_count_;
2110 if (!callback.is_null())
2111 callback.Run();
2114 int flush_count() { return flush_count_; }
2116 private:
2117 ~FlushablePersistentStore() override {}
2119 volatile int flush_count_;
2122 // Counts the number of times Callback() has been run.
2123 class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> {
2124 public:
2125 CallbackCounter() : callback_count_(0) {}
2127 void Callback() { ++callback_count_; }
2129 int callback_count() { return callback_count_; }
2131 private:
2132 friend class base::RefCountedThreadSafe<CallbackCounter>;
2133 ~CallbackCounter() {}
2135 volatile int callback_count_;
2138 } // namespace
2140 // Test that FlushStore() is forwarded to the store and callbacks are posted.
2141 TEST_F(CookieMonsterTest, FlushStore) {
2142 scoped_refptr<CallbackCounter> counter(new CallbackCounter());
2143 scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
2144 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2146 ASSERT_EQ(0, store->flush_count());
2147 ASSERT_EQ(0, counter->callback_count());
2149 // Before initialization, FlushStore() should just run the callback.
2150 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2151 base::MessageLoop::current()->RunUntilIdle();
2153 ASSERT_EQ(0, store->flush_count());
2154 ASSERT_EQ(1, counter->callback_count());
2156 // NULL callback is safe.
2157 cm->FlushStore(base::Closure());
2158 base::MessageLoop::current()->RunUntilIdle();
2160 ASSERT_EQ(0, store->flush_count());
2161 ASSERT_EQ(1, counter->callback_count());
2163 // After initialization, FlushStore() should delegate to the store.
2164 GetAllCookies(cm.get()); // Force init.
2165 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2166 base::MessageLoop::current()->RunUntilIdle();
2168 ASSERT_EQ(1, store->flush_count());
2169 ASSERT_EQ(2, counter->callback_count());
2171 // NULL callback is still safe.
2172 cm->FlushStore(base::Closure());
2173 base::MessageLoop::current()->RunUntilIdle();
2175 ASSERT_EQ(2, store->flush_count());
2176 ASSERT_EQ(2, counter->callback_count());
2178 // If there's no backing store, FlushStore() is always a safe no-op.
2179 cm = new CookieMonster(NULL, NULL);
2180 GetAllCookies(cm.get()); // Force init.
2181 cm->FlushStore(base::Closure());
2182 base::MessageLoop::current()->RunUntilIdle();
2184 ASSERT_EQ(2, counter->callback_count());
2186 cm->FlushStore(base::Bind(&CallbackCounter::Callback, counter.get()));
2187 base::MessageLoop::current()->RunUntilIdle();
2189 ASSERT_EQ(3, counter->callback_count());
2192 TEST_F(CookieMonsterTest, SetAllCookies) {
2193 scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
2194 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2195 cm->SetPersistSessionCookies(true);
2197 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "U=V; path=/"));
2198 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "W=X; path=/foo"));
2199 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "Y=Z; path=/"));
2201 CookieList list;
2202 list.push_back(CanonicalCookie(url_google_, "A", "B", url_google_.host(), "/",
2203 base::Time::Now(), base::Time(), base::Time(),
2204 false, false, false, COOKIE_PRIORITY_DEFAULT));
2205 list.push_back(CanonicalCookie(url_google_, "W", "X", url_google_.host(),
2206 "/bar", base::Time::Now(), base::Time(),
2207 base::Time(), false, false, false,
2208 COOKIE_PRIORITY_DEFAULT));
2209 list.push_back(CanonicalCookie(url_google_, "Y", "Z", url_google_.host(), "/",
2210 base::Time::Now(), base::Time(), base::Time(),
2211 false, false, false, COOKIE_PRIORITY_DEFAULT));
2213 // SetAllCookies must not flush.
2214 ASSERT_EQ(0, store->flush_count());
2215 EXPECT_TRUE(SetAllCookies(cm.get(), list));
2216 EXPECT_EQ(0, store->flush_count());
2218 CookieList cookies = GetAllCookies(cm.get());
2219 size_t expected_size = 3; // "A", "W" and "Y". "U" is gone.
2220 EXPECT_EQ(expected_size, cookies.size());
2221 CookieList::iterator it = cookies.begin();
2223 ASSERT_TRUE(it != cookies.end());
2224 EXPECT_EQ("W", it->Name());
2225 EXPECT_EQ("X", it->Value());
2226 EXPECT_EQ("/bar", it->Path()); // The path has been updated.
2228 ASSERT_TRUE(++it != cookies.end());
2229 EXPECT_EQ("A", it->Name());
2230 EXPECT_EQ("B", it->Value());
2232 ASSERT_TRUE(++it != cookies.end());
2233 EXPECT_EQ("Y", it->Name());
2234 EXPECT_EQ("Z", it->Value());
2237 TEST_F(CookieMonsterTest, ComputeCookieDiff) {
2238 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2240 base::Time now = base::Time::Now();
2241 base::Time creation_time = now - base::TimeDelta::FromSeconds(1);
2243 CanonicalCookie cookie1(url_google_, "A", "B", url_google_.host(), "/",
2244 creation_time, base::Time(), base::Time(), false,
2245 false, false, COOKIE_PRIORITY_DEFAULT);
2246 CanonicalCookie cookie2(url_google_, "C", "D", url_google_.host(), "/",
2247 creation_time, base::Time(), base::Time(), false,
2248 false, false, COOKIE_PRIORITY_DEFAULT);
2249 CanonicalCookie cookie3(url_google_, "E", "F", url_google_.host(), "/",
2250 creation_time, base::Time(), base::Time(), false,
2251 false, false, COOKIE_PRIORITY_DEFAULT);
2252 CanonicalCookie cookie4(url_google_, "G", "H", url_google_.host(), "/",
2253 creation_time, base::Time(), base::Time(), false,
2254 false, false, COOKIE_PRIORITY_DEFAULT);
2255 CanonicalCookie cookie4_with_new_value(
2256 url_google_, "G", "iamnew", url_google_.host(), "/", creation_time,
2257 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
2258 CanonicalCookie cookie5(url_google_, "I", "J", url_google_.host(), "/",
2259 creation_time, base::Time(), base::Time(), false,
2260 false, false, COOKIE_PRIORITY_DEFAULT);
2261 CanonicalCookie cookie5_with_new_creation_time(
2262 url_google_, "I", "J", url_google_.host(), "/", now, base::Time(),
2263 base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
2264 CanonicalCookie cookie6(url_google_, "K", "L", url_google_.host(), "/foo",
2265 creation_time, base::Time(), base::Time(), false,
2266 false, false, COOKIE_PRIORITY_DEFAULT);
2267 CanonicalCookie cookie6_with_new_path(
2268 url_google_, "K", "L", url_google_.host(), "/bar", creation_time,
2269 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
2270 CanonicalCookie cookie7(url_google_, "M", "N", url_google_.host(), "/foo",
2271 creation_time, base::Time(), base::Time(), false,
2272 false, false, COOKIE_PRIORITY_DEFAULT);
2273 CanonicalCookie cookie7_with_new_path(
2274 url_google_, "M", "N", url_google_.host(), "/bar", creation_time,
2275 base::Time(), base::Time(), false, false, false, COOKIE_PRIORITY_DEFAULT);
2277 CookieList old_cookies;
2278 old_cookies.push_back(cookie1);
2279 old_cookies.push_back(cookie2);
2280 old_cookies.push_back(cookie4);
2281 old_cookies.push_back(cookie5);
2282 old_cookies.push_back(cookie6);
2283 old_cookies.push_back(cookie7);
2285 CookieList new_cookies;
2286 new_cookies.push_back(cookie1);
2287 new_cookies.push_back(cookie3);
2288 new_cookies.push_back(cookie4_with_new_value);
2289 new_cookies.push_back(cookie5_with_new_creation_time);
2290 new_cookies.push_back(cookie6_with_new_path);
2291 new_cookies.push_back(cookie7);
2292 new_cookies.push_back(cookie7_with_new_path);
2294 CookieList cookies_to_add;
2295 CookieList cookies_to_delete;
2297 cm->ComputeCookieDiff(&old_cookies, &new_cookies, &cookies_to_add,
2298 &cookies_to_delete);
2300 // |cookie1| has not changed.
2301 EXPECT_FALSE(IsCookieInList(cookie1, cookies_to_add));
2302 EXPECT_FALSE(IsCookieInList(cookie1, cookies_to_delete));
2304 // |cookie2| has been deleted.
2305 EXPECT_FALSE(IsCookieInList(cookie2, cookies_to_add));
2306 EXPECT_TRUE(IsCookieInList(cookie2, cookies_to_delete));
2308 // |cookie3| has been added.
2309 EXPECT_TRUE(IsCookieInList(cookie3, cookies_to_add));
2310 EXPECT_FALSE(IsCookieInList(cookie3, cookies_to_delete));
2312 // |cookie4| has a new value: new cookie overrides the old one (which does not
2313 // need to be explicitly removed).
2314 EXPECT_FALSE(IsCookieInList(cookie4, cookies_to_add));
2315 EXPECT_FALSE(IsCookieInList(cookie4, cookies_to_delete));
2316 EXPECT_TRUE(IsCookieInList(cookie4_with_new_value, cookies_to_add));
2317 EXPECT_FALSE(IsCookieInList(cookie4_with_new_value, cookies_to_delete));
2319 // |cookie5| has a new creation time: new cookie overrides the old one (which
2320 // does not need to be explicitly removed).
2321 EXPECT_FALSE(IsCookieInList(cookie5, cookies_to_add));
2322 EXPECT_FALSE(IsCookieInList(cookie5, cookies_to_delete));
2323 EXPECT_TRUE(IsCookieInList(cookie5_with_new_creation_time, cookies_to_add));
2324 EXPECT_FALSE(
2325 IsCookieInList(cookie5_with_new_creation_time, cookies_to_delete));
2327 // |cookie6| has a new path: the new cookie does not overrides the old one,
2328 // which needs to be explicitly removed.
2329 EXPECT_FALSE(IsCookieInList(cookie6, cookies_to_add));
2330 EXPECT_TRUE(IsCookieInList(cookie6, cookies_to_delete));
2331 EXPECT_TRUE(IsCookieInList(cookie6_with_new_path, cookies_to_add));
2332 EXPECT_FALSE(IsCookieInList(cookie6_with_new_path, cookies_to_delete));
2334 // |cookie7| is kept and |cookie7_with_new_path| is added as a new cookie.
2335 EXPECT_FALSE(IsCookieInList(cookie7, cookies_to_add));
2336 EXPECT_FALSE(IsCookieInList(cookie7, cookies_to_delete));
2337 EXPECT_TRUE(IsCookieInList(cookie7_with_new_path, cookies_to_add));
2338 EXPECT_FALSE(IsCookieInList(cookie7_with_new_path, cookies_to_delete));
2341 // Check that DeleteAll does flush (as a sanity check that flush_count()
2342 // works).
2343 TEST_F(CookieMonsterTest, DeleteAll) {
2344 scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
2345 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2346 cm->SetPersistSessionCookies(true);
2348 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "X=Y; path=/"));
2350 ASSERT_EQ(0, store->flush_count());
2351 EXPECT_EQ(1, DeleteAll(cm.get()));
2352 EXPECT_EQ(1, store->flush_count());
2355 TEST_F(CookieMonsterTest, HistogramCheck) {
2356 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2357 // Should match call in InitializeHistograms, but doesn't really matter
2358 // since the histogram should have been initialized by the CM construction
2359 // above.
2360 base::HistogramBase* expired_histogram = base::Histogram::FactoryGet(
2361 "Cookie.ExpirationDurationMinutes", 1, 10 * 365 * 24 * 60, 50,
2362 base::Histogram::kUmaTargetedHistogramFlag);
2364 scoped_ptr<base::HistogramSamples> samples1(
2365 expired_histogram->SnapshotSamples());
2366 ASSERT_TRUE(SetCookieWithDetails(
2367 cm.get(), GURL("http://fake.a.url"), "a", "b", "a.url", "/",
2368 base::Time::Now() + base::TimeDelta::FromMinutes(59), false, false, false,
2369 COOKIE_PRIORITY_DEFAULT));
2371 scoped_ptr<base::HistogramSamples> samples2(
2372 expired_histogram->SnapshotSamples());
2373 EXPECT_EQ(samples1->TotalCount() + 1, samples2->TotalCount());
2375 // kValidCookieLine creates a session cookie.
2376 ASSERT_TRUE(SetCookie(cm.get(), url_google_, kValidCookieLine));
2378 scoped_ptr<base::HistogramSamples> samples3(
2379 expired_histogram->SnapshotSamples());
2380 EXPECT_EQ(samples2->TotalCount(), samples3->TotalCount());
2383 namespace {
2385 class MultiThreadedCookieMonsterTest : public CookieMonsterTest {
2386 public:
2387 MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {}
2389 // Helper methods for calling the asynchronous CookieMonster methods
2390 // from a different thread.
2392 void GetAllCookiesTask(CookieMonster* cm, GetCookieListCallback* callback) {
2393 cm->GetAllCookiesAsync(
2394 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2397 void GetAllCookiesForURLTask(CookieMonster* cm,
2398 const GURL& url,
2399 GetCookieListCallback* callback) {
2400 cm->GetAllCookiesForURLAsync(url, base::Bind(&GetCookieListCallback::Run,
2401 base::Unretained(callback)));
2404 void GetAllCookiesForURLWithOptionsTask(CookieMonster* cm,
2405 const GURL& url,
2406 const CookieOptions& options,
2407 GetCookieListCallback* callback) {
2408 cm->GetAllCookiesForURLWithOptionsAsync(
2409 url, options,
2410 base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
2413 void SetCookieWithDetailsTask(CookieMonster* cm,
2414 const GURL& url,
2415 ResultSavingCookieCallback<bool>* callback) {
2416 // Define the parameters here instead of in the calling fucntion.
2417 // The maximum number of parameters for Bind function is 6.
2418 std::string name = "A";
2419 std::string value = "B";
2420 std::string domain = std::string();
2421 std::string path = "/foo";
2422 base::Time expiration_time = base::Time();
2423 bool secure = false;
2424 bool http_only = false;
2425 bool first_party_only = false;
2426 CookiePriority priority = COOKIE_PRIORITY_DEFAULT;
2427 cm->SetCookieWithDetailsAsync(
2428 url, name, value, domain, path, expiration_time, secure, http_only,
2429 first_party_only, priority,
2430 base::Bind(&ResultSavingCookieCallback<bool>::Run,
2431 base::Unretained(callback)));
2434 void DeleteAllCreatedBetweenTask(CookieMonster* cm,
2435 const base::Time& delete_begin,
2436 const base::Time& delete_end,
2437 ResultSavingCookieCallback<int>* callback) {
2438 cm->DeleteAllCreatedBetweenAsync(
2439 delete_begin, delete_end,
2440 base::Bind(&ResultSavingCookieCallback<int>::Run,
2441 base::Unretained(callback)));
2444 void DeleteAllForHostTask(CookieMonster* cm,
2445 const GURL& url,
2446 ResultSavingCookieCallback<int>* callback) {
2447 cm->DeleteAllForHostAsync(url,
2448 base::Bind(&ResultSavingCookieCallback<int>::Run,
2449 base::Unretained(callback)));
2452 void DeleteAllCreatedBetweenForHostTask(
2453 CookieMonster* cm,
2454 const base::Time delete_begin,
2455 const base::Time delete_end,
2456 const GURL& url,
2457 ResultSavingCookieCallback<int>* callback) {
2458 cm->DeleteAllCreatedBetweenForHostAsync(
2459 delete_begin, delete_end, url,
2460 base::Bind(&ResultSavingCookieCallback<int>::Run,
2461 base::Unretained(callback)));
2464 void DeleteCanonicalCookieTask(CookieMonster* cm,
2465 const CanonicalCookie& cookie,
2466 ResultSavingCookieCallback<bool>* callback) {
2467 cm->DeleteCanonicalCookieAsync(
2468 cookie, base::Bind(&ResultSavingCookieCallback<bool>::Run,
2469 base::Unretained(callback)));
2472 protected:
2473 void RunOnOtherThread(const base::Closure& task) {
2474 other_thread_.Start();
2475 other_thread_.task_runner()->PostTask(FROM_HERE, task);
2476 RunFor(kTimeout);
2477 other_thread_.Stop();
2480 Thread other_thread_;
2483 } // namespace
2485 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookies) {
2486 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2487 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2488 CookieList cookies = GetAllCookies(cm.get());
2489 CookieList::const_iterator it = cookies.begin();
2490 ASSERT_TRUE(it != cookies.end());
2491 EXPECT_EQ("www.google.izzle", it->Domain());
2492 EXPECT_EQ("A", it->Name());
2493 ASSERT_TRUE(++it == cookies.end());
2494 GetCookieListCallback callback(&other_thread_);
2495 base::Closure task =
2496 base::Bind(&MultiThreadedCookieMonsterTest::GetAllCookiesTask,
2497 base::Unretained(this), cm, &callback);
2498 RunOnOtherThread(task);
2499 EXPECT_TRUE(callback.did_run());
2500 it = callback.cookies().begin();
2501 ASSERT_TRUE(it != callback.cookies().end());
2502 EXPECT_EQ("www.google.izzle", it->Domain());
2503 EXPECT_EQ("A", it->Name());
2504 ASSERT_TRUE(++it == callback.cookies().end());
2507 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURL) {
2508 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2509 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2510 CookieList cookies = GetAllCookiesForURL(cm.get(), url_google_);
2511 CookieList::const_iterator it = cookies.begin();
2512 ASSERT_TRUE(it != cookies.end());
2513 EXPECT_EQ("www.google.izzle", it->Domain());
2514 EXPECT_EQ("A", it->Name());
2515 ASSERT_TRUE(++it == cookies.end());
2516 GetCookieListCallback callback(&other_thread_);
2517 base::Closure task =
2518 base::Bind(&MultiThreadedCookieMonsterTest::GetAllCookiesForURLTask,
2519 base::Unretained(this), cm, url_google_, &callback);
2520 RunOnOtherThread(task);
2521 EXPECT_TRUE(callback.did_run());
2522 it = callback.cookies().begin();
2523 ASSERT_TRUE(it != callback.cookies().end());
2524 EXPECT_EQ("www.google.izzle", it->Domain());
2525 EXPECT_EQ("A", it->Name());
2526 ASSERT_TRUE(++it == callback.cookies().end());
2529 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURLWithOpt) {
2530 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2531 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2532 CookieOptions options;
2533 CookieList cookies =
2534 GetAllCookiesForURLWithOptions(cm.get(), url_google_, options);
2535 CookieList::const_iterator it = cookies.begin();
2536 ASSERT_TRUE(it != cookies.end());
2537 EXPECT_EQ("www.google.izzle", it->Domain());
2538 EXPECT_EQ("A", it->Name());
2539 ASSERT_TRUE(++it == cookies.end());
2540 GetCookieListCallback callback(&other_thread_);
2541 base::Closure task = base::Bind(
2542 &MultiThreadedCookieMonsterTest::GetAllCookiesForURLWithOptionsTask,
2543 base::Unretained(this), cm, url_google_, options, &callback);
2544 RunOnOtherThread(task);
2545 EXPECT_TRUE(callback.did_run());
2546 it = callback.cookies().begin();
2547 ASSERT_TRUE(it != callback.cookies().end());
2548 EXPECT_EQ("www.google.izzle", it->Domain());
2549 EXPECT_EQ("A", it->Name());
2550 ASSERT_TRUE(++it == callback.cookies().end());
2553 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) {
2554 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2555 EXPECT_TRUE(SetCookieWithDetails(cm.get(), url_google_foo_, "A", "B",
2556 std::string(), "/foo", base::Time(), false,
2557 false, false, COOKIE_PRIORITY_DEFAULT));
2558 ResultSavingCookieCallback<bool> callback(&other_thread_);
2559 base::Closure task =
2560 base::Bind(&MultiThreadedCookieMonsterTest::SetCookieWithDetailsTask,
2561 base::Unretained(this), cm, url_google_foo_, &callback);
2562 RunOnOtherThread(task);
2563 EXPECT_TRUE(callback.did_run());
2564 EXPECT_TRUE(callback.result());
2567 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllCreatedBetween) {
2568 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2569 CookieOptions options;
2570 Time now = Time::Now();
2571 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2572 EXPECT_EQ(1, DeleteAllCreatedBetween(cm.get(), now - TimeDelta::FromDays(99),
2573 Time()));
2574 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2575 ResultSavingCookieCallback<int> callback(&other_thread_);
2576 base::Closure task =
2577 base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenTask,
2578 base::Unretained(this), cm, now - TimeDelta::FromDays(99),
2579 Time(), &callback);
2580 RunOnOtherThread(task);
2581 EXPECT_TRUE(callback.did_run());
2582 EXPECT_EQ(1, callback.result());
2585 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllForHost) {
2586 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2587 CookieOptions options;
2588 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2589 EXPECT_EQ(1, DeleteAllForHost(cm.get(), url_google_));
2590 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2591 ResultSavingCookieCallback<int> callback(&other_thread_);
2592 base::Closure task =
2593 base::Bind(&MultiThreadedCookieMonsterTest::DeleteAllForHostTask,
2594 base::Unretained(this), cm, url_google_, &callback);
2595 RunOnOtherThread(task);
2596 EXPECT_TRUE(callback.did_run());
2597 EXPECT_EQ(1, callback.result());
2600 TEST_F(MultiThreadedCookieMonsterTest,
2601 ThreadCheckDeleteAllCreatedBetweenForHost) {
2602 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2603 GURL url_not_google("http://www.notgoogle.com");
2605 CookieOptions options;
2606 Time now = Time::Now();
2607 // ago1 < ago2 < ago3 < now.
2608 Time ago1 = now - TimeDelta::FromDays(101);
2609 Time ago2 = now - TimeDelta::FromDays(100);
2610 Time ago3 = now - TimeDelta::FromDays(99);
2612 // These 3 cookies match the first deletion.
2613 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2614 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "C=D", options));
2615 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "Y=Z", options));
2617 // This cookie does not match host.
2618 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_not_google, "E=F", options));
2620 // This cookie does not match time range: [ago3, inf], for first deletion, but
2621 // matches for the second deletion.
2622 EXPECT_TRUE(cm->SetCookieWithCreationTime(url_google_, "G=H", ago2));
2624 // 1. First set of deletions.
2625 EXPECT_EQ(
2626 3, // Deletes A=B, C=D, Y=Z
2627 DeleteAllCreatedBetweenForHost(cm.get(), ago3, Time::Max(), url_google_));
2629 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2630 ResultSavingCookieCallback<int> callback(&other_thread_);
2632 // 2. Second set of deletions.
2633 base::Closure task = base::Bind(
2634 &MultiThreadedCookieMonsterTest::DeleteAllCreatedBetweenForHostTask,
2635 base::Unretained(this), cm, ago1, Time(), url_google_, &callback);
2636 RunOnOtherThread(task);
2637 EXPECT_TRUE(callback.did_run());
2638 EXPECT_EQ(2, callback.result()); // Deletes A=B, G=H.
2641 TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) {
2642 scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
2643 CookieOptions options;
2644 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2645 CookieList cookies = GetAllCookies(cm.get());
2646 CookieList::iterator it = cookies.begin();
2647 EXPECT_TRUE(DeleteCanonicalCookie(cm.get(), *it));
2649 EXPECT_TRUE(SetCookieWithOptions(cm.get(), url_google_, "A=B", options));
2650 ResultSavingCookieCallback<bool> callback(&other_thread_);
2651 cookies = GetAllCookies(cm.get());
2652 it = cookies.begin();
2653 base::Closure task =
2654 base::Bind(&MultiThreadedCookieMonsterTest::DeleteCanonicalCookieTask,
2655 base::Unretained(this), cm, *it, &callback);
2656 RunOnOtherThread(task);
2657 EXPECT_TRUE(callback.did_run());
2658 EXPECT_TRUE(callback.result());
2661 // Ensure that cookies for http, https, ws, and wss all share the same storage
2662 // and policies when GetAllCookiesForURLAsync is used. This test is part of
2663 // MultiThreadedCookieMonsterTest in order to test and use
2664 // GetAllCookiesForURLAsync, but it does not use any additional threads.
2665 TEST_F(MultiThreadedCookieMonsterTest, GetAllCookiesForURLEffectiveDomain) {
2666 std::vector<CanonicalCookie*> cookies;
2667 // This cookie will be freed by the CookieMonster.
2668 cookies.push_back(CanonicalCookie::Create(url_google_, kValidCookieLine,
2669 Time::Now(), CookieOptions()));
2670 CanonicalCookie cookie = *cookies[0];
2671 scoped_refptr<NewMockPersistentCookieStore> store(
2672 new NewMockPersistentCookieStore);
2673 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2675 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback;
2676 ::testing::StrictMock<::testing::MockFunction<void(int)>> checkpoint;
2677 const std::string key =
2678 cookie_util::GetEffectiveDomain(url_google_.scheme(), url_google_.host());
2680 ::testing::InSequence s;
2681 EXPECT_CALL(checkpoint, Call(0));
2682 EXPECT_CALL(*store, Load(::testing::_));
2683 EXPECT_CALL(*store, LoadCookiesForKey(key, ::testing::_))
2684 .WillOnce(::testing::SaveArg<1>(&loaded_callback));
2685 EXPECT_CALL(checkpoint, Call(1));
2686 // LoadCookiesForKey will never be called after checkpoint.Call(1) although
2687 // we will call GetAllCookiesForURLAsync again, because all URLs below share
2688 // the same key.
2689 EXPECT_CALL(*store, LoadCookiesForKey(::testing::_, ::testing::_)).Times(0);
2691 GetCookieListCallback callback;
2692 checkpoint.Call(0);
2693 GetAllCookiesForURLTask(cm.get(), url_google_, &callback);
2694 checkpoint.Call(1);
2695 ASSERT_FALSE(callback.did_run());
2696 // Pass the cookies to the CookieMonster.
2697 loaded_callback.Run(cookies);
2698 // Now GetAllCookiesForURLTask is done.
2699 ASSERT_TRUE(callback.did_run());
2700 // See that the callback was called with the cookies.
2701 ASSERT_EQ(1u, callback.cookies().size());
2702 EXPECT_TRUE(cookie.IsEquivalent(callback.cookies()[0]));
2704 // All urls in |urls| should share the same cookie domain.
2705 const GURL kUrls[] = {
2706 url_google_,
2707 url_google_secure_,
2708 GURL(kUrlGoogleWebSocket),
2709 GURL(kUrlGoogleWebSocketSecure),
2711 for (const GURL& url : kUrls) {
2712 // Call the function with |url| and verify it is done synchronously without
2713 // calling LoadCookiesForKey.
2714 GetCookieListCallback callback;
2715 GetAllCookiesForURLTask(cm.get(), url, &callback);
2716 ASSERT_TRUE(callback.did_run());
2717 ASSERT_EQ(1u, callback.cookies().size());
2718 EXPECT_TRUE(cookie.IsEquivalent(callback.cookies()[0]));
2722 TEST_F(CookieMonsterTest, InvalidExpiryTime) {
2723 std::string cookie_line =
2724 std::string(kValidCookieLine) + "; expires=Blarg arg arg";
2725 scoped_ptr<CanonicalCookie> cookie(CanonicalCookie::Create(
2726 url_google_, cookie_line, Time::Now(), CookieOptions()));
2727 ASSERT_FALSE(cookie->IsPersistent());
2730 // Test that CookieMonster writes session cookies into the underlying
2731 // CookieStore if the "persist session cookies" option is on.
2732 TEST_F(CookieMonsterTest, PersistSessionCookies) {
2733 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
2734 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2735 cm->SetPersistSessionCookies(true);
2737 // All cookies set with SetCookie are session cookies.
2738 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B"));
2739 EXPECT_EQ("A=B", GetCookies(cm.get(), url_google_));
2741 // The cookie was written to the backing store.
2742 EXPECT_EQ(1u, store->commands().size());
2743 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
2744 EXPECT_EQ("A", store->commands()[0].cookie.Name());
2745 EXPECT_EQ("B", store->commands()[0].cookie.Value());
2747 // Modify the cookie.
2748 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=C"));
2749 EXPECT_EQ("A=C", GetCookies(cm.get(), url_google_));
2750 EXPECT_EQ(3u, store->commands().size());
2751 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2752 EXPECT_EQ("A", store->commands()[1].cookie.Name());
2753 EXPECT_EQ("B", store->commands()[1].cookie.Value());
2754 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
2755 EXPECT_EQ("A", store->commands()[2].cookie.Name());
2756 EXPECT_EQ("C", store->commands()[2].cookie.Value());
2758 // Delete the cookie.
2759 DeleteCookie(cm.get(), url_google_, "A");
2760 EXPECT_EQ("", GetCookies(cm.get(), url_google_));
2761 EXPECT_EQ(4u, store->commands().size());
2762 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
2763 EXPECT_EQ("A", store->commands()[3].cookie.Name());
2764 EXPECT_EQ("C", store->commands()[3].cookie.Value());
2767 // Test the commands sent to the persistent cookie store.
2768 TEST_F(CookieMonsterTest, PersisentCookieStorageTest) {
2769 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
2770 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2772 // Add a cookie.
2773 EXPECT_TRUE(SetCookie(cm.get(), url_google_,
2774 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2775 this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
2776 ASSERT_EQ(1u, store->commands().size());
2777 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type);
2778 // Remove it.
2779 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B; max-age=0"));
2780 this->MatchCookieLines(std::string(), GetCookies(cm.get(), url_google_));
2781 ASSERT_EQ(2u, store->commands().size());
2782 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type);
2784 // Add a cookie.
2785 EXPECT_TRUE(SetCookie(cm.get(), url_google_,
2786 "A=B; expires=Mon, 18-Apr-22 22:50:13 GMT"));
2787 this->MatchCookieLines("A=B", GetCookies(cm.get(), url_google_));
2788 ASSERT_EQ(3u, store->commands().size());
2789 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type);
2790 // Overwrite it.
2791 EXPECT_TRUE(SetCookie(cm.get(), url_google_,
2792 "A=Foo; expires=Mon, 18-Apr-22 22:50:14 GMT"));
2793 this->MatchCookieLines("A=Foo", GetCookies(cm.get(), url_google_));
2794 ASSERT_EQ(5u, store->commands().size());
2795 EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
2796 EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[4].type);
2798 // Create some non-persistent cookies and check that they don't go to the
2799 // persistent storage.
2800 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "B=Bar"));
2801 this->MatchCookieLines("A=Foo; B=Bar", GetCookies(cm.get(), url_google_));
2802 EXPECT_EQ(5u, store->commands().size());
2805 // Test to assure that cookies with control characters are purged appropriately.
2806 // See http://crbug.com/238041 for background.
2807 TEST_F(CookieMonsterTest, ControlCharacterPurge) {
2808 const Time now1(Time::Now());
2809 const Time now2(Time::Now() + TimeDelta::FromSeconds(1));
2810 const Time now3(Time::Now() + TimeDelta::FromSeconds(2));
2811 const Time later(now1 + TimeDelta::FromDays(1));
2812 const GURL url("http://host/path");
2813 const std::string domain("host");
2814 const std::string path("/path");
2816 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
2818 std::vector<CanonicalCookie*> initial_cookies;
2820 AddCookieToList(domain, "foo=bar; path=" + path, now1, &initial_cookies);
2822 // We have to manually build this cookie because it contains a control
2823 // character, and our cookie line parser rejects control characters.
2824 CanonicalCookie* cc =
2825 new CanonicalCookie(url, "baz",
2826 "\x05"
2827 "boo",
2828 domain, path, now2, later, now2, false, false, false,
2829 COOKIE_PRIORITY_DEFAULT);
2830 initial_cookies.push_back(cc);
2832 AddCookieToList(domain, "hello=world; path=" + path, now3, &initial_cookies);
2834 // Inject our initial cookies into the mock PersistentCookieStore.
2835 store->SetLoadExpectation(true, initial_cookies);
2837 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2839 EXPECT_EQ("foo=bar; hello=world", GetCookies(cm.get(), url));
2842 // Test that cookie source schemes are histogrammed correctly.
2843 TEST_F(CookieMonsterTest, CookieSourceHistogram) {
2844 base::HistogramTester histograms;
2845 const std::string cookie_source_histogram = "Cookie.CookieSourceScheme";
2847 scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
2848 scoped_refptr<CookieMonster> cm(new CookieMonster(store.get(), NULL));
2850 histograms.ExpectTotalCount(cookie_source_histogram, 0);
2852 // Set a Secure cookie on a cryptographic scheme.
2853 EXPECT_TRUE(SetCookie(cm.get(), url_google_secure_, "A=B; path=/; Secure"));
2854 histograms.ExpectTotalCount(cookie_source_histogram, 1);
2855 histograms.ExpectBucketCount(
2856 cookie_source_histogram,
2857 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME, 1);
2859 // Set a non-Secure cookie on a cryptographic scheme.
2860 EXPECT_TRUE(SetCookie(cm.get(), url_google_secure_, "C=D; path=/;"));
2861 histograms.ExpectTotalCount(cookie_source_histogram, 2);
2862 histograms.ExpectBucketCount(
2863 cookie_source_histogram,
2864 CookieMonster::COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME, 1);
2866 // Set a Secure cookie on a non-cryptographic scheme.
2867 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "D=E; path=/; Secure"));
2868 histograms.ExpectTotalCount(cookie_source_histogram, 3);
2869 histograms.ExpectBucketCount(
2870 cookie_source_histogram,
2871 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME, 1);
2873 // Overwrite a Secure cookie (set by a cryptographic scheme) on a
2874 // non-cryptographic scheme.
2875 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "A=B; path=/; Secure"));
2876 histograms.ExpectTotalCount(cookie_source_histogram, 4);
2877 histograms.ExpectBucketCount(
2878 cookie_source_histogram,
2879 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME, 1);
2880 histograms.ExpectBucketCount(
2881 cookie_source_histogram,
2882 CookieMonster::COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME, 2);
2884 // Test that clearing a Secure cookie on a http:// URL does not get
2885 // counted.
2886 EXPECT_TRUE(SetCookie(cm.get(), url_google_secure_, "F=G; path=/; Secure"));
2887 histograms.ExpectTotalCount(cookie_source_histogram, 5);
2888 std::string cookies1 = GetCookies(cm.get(), url_google_secure_);
2889 EXPECT_NE(std::string::npos, cookies1.find("F=G"));
2890 EXPECT_TRUE(SetCookie(cm.get(), url_google_,
2891 "F=G; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"));
2892 std::string cookies2 = GetCookies(cm.get(), url_google_secure_);
2893 EXPECT_EQ(std::string::npos, cookies2.find("F=G"));
2894 histograms.ExpectTotalCount(cookie_source_histogram, 5);
2896 // Set a non-Secure cookie on a non-cryptographic scheme.
2897 EXPECT_TRUE(SetCookie(cm.get(), url_google_, "H=I; path=/"));
2898 histograms.ExpectTotalCount(cookie_source_histogram, 6);
2899 histograms.ExpectBucketCount(
2900 cookie_source_histogram,
2901 CookieMonster::COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME, 1);
2904 class CookieMonsterNotificationTest : public CookieMonsterTest {
2905 public:
2906 CookieMonsterNotificationTest()
2907 : test_url_("http://www.google.com/foo"),
2908 store_(new MockPersistentCookieStore),
2909 monster_(new CookieMonster(store_.get(), NULL)) {}
2911 ~CookieMonsterNotificationTest() override {}
2913 CookieMonster* monster() { return monster_.get(); }
2915 protected:
2916 const GURL test_url_;
2918 private:
2919 scoped_refptr<MockPersistentCookieStore> store_;
2920 scoped_refptr<CookieMonster> monster_;
2923 void RecordCookieChanges(std::vector<CanonicalCookie>* out_cookies,
2924 std::vector<bool>* out_removes,
2925 const CanonicalCookie& cookie,
2926 bool removed) {
2927 DCHECK(out_cookies);
2928 out_cookies->push_back(cookie);
2929 if (out_removes)
2930 out_removes->push_back(removed);
2933 TEST_F(CookieMonsterNotificationTest, NoNotifyWithNoCookie) {
2934 std::vector<CanonicalCookie> cookies;
2935 scoped_ptr<CookieStore::CookieChangedSubscription> sub(
2936 monster()->AddCallbackForCookie(
2937 test_url_, "abc",
2938 base::Bind(&RecordCookieChanges, &cookies, nullptr)));
2939 base::MessageLoop::current()->RunUntilIdle();
2940 EXPECT_EQ(0U, cookies.size());
2943 TEST_F(CookieMonsterNotificationTest, NoNotifyWithInitialCookie) {
2944 std::vector<CanonicalCookie> cookies;
2945 SetCookie(monster(), test_url_, "abc=def");
2946 base::MessageLoop::current()->RunUntilIdle();
2947 scoped_ptr<CookieStore::CookieChangedSubscription> sub(
2948 monster()->AddCallbackForCookie(
2949 test_url_, "abc",
2950 base::Bind(&RecordCookieChanges, &cookies, nullptr)));
2951 base::MessageLoop::current()->RunUntilIdle();
2952 EXPECT_EQ(0U, cookies.size());
2955 TEST_F(CookieMonsterNotificationTest, NotifyOnSet) {
2956 std::vector<CanonicalCookie> cookies;
2957 std::vector<bool> removes;
2958 scoped_ptr<CookieStore::CookieChangedSubscription> sub(
2959 monster()->AddCallbackForCookie(
2960 test_url_, "abc",
2961 base::Bind(&RecordCookieChanges, &cookies, &removes)));
2962 SetCookie(monster(), test_url_, "abc=def");
2963 base::MessageLoop::current()->RunUntilIdle();
2964 EXPECT_EQ(1U, cookies.size());
2965 EXPECT_EQ(1U, removes.size());
2967 EXPECT_EQ("abc", cookies[0].Name());
2968 EXPECT_EQ("def", cookies[0].Value());
2969 EXPECT_FALSE(removes[0]);
2972 TEST_F(CookieMonsterNotificationTest, NotifyOnDelete) {
2973 std::vector<CanonicalCookie> cookies;
2974 std::vector<bool> removes;
2975 scoped_ptr<CookieStore::CookieChangedSubscription> sub(
2976 monster()->AddCallbackForCookie(
2977 test_url_, "abc",
2978 base::Bind(&RecordCookieChanges, &cookies, &removes)));
2979 SetCookie(monster(), test_url_, "abc=def");
2980 base::MessageLoop::current()->RunUntilIdle();
2981 EXPECT_EQ(1U, cookies.size());
2982 EXPECT_EQ(1U, removes.size());
2984 DeleteCookie(monster(), test_url_, "abc");
2985 base::MessageLoop::current()->RunUntilIdle();
2986 EXPECT_EQ(2U, cookies.size());
2987 EXPECT_EQ(2U, removes.size());
2989 EXPECT_EQ("abc", cookies[1].Name());
2990 EXPECT_EQ("def", cookies[1].Value());
2991 EXPECT_TRUE(removes[1]);
2994 TEST_F(CookieMonsterNotificationTest, NotifyOnUpdate) {
2995 std::vector<CanonicalCookie> cookies;
2996 std::vector<bool> removes;
2997 scoped_ptr<CookieStore::CookieChangedSubscription> sub(
2998 monster()->AddCallbackForCookie(
2999 test_url_, "abc",
3000 base::Bind(&RecordCookieChanges, &cookies, &removes)));
3001 SetCookie(monster(), test_url_, "abc=def");
3002 base::MessageLoop::current()->RunUntilIdle();
3003 EXPECT_EQ(1U, cookies.size());
3005 // Replacing an existing cookie is actually a two-phase delete + set
3006 // operation, so we get an extra notification.
3007 SetCookie(monster(), test_url_, "abc=ghi");
3008 base::MessageLoop::current()->RunUntilIdle();
3010 EXPECT_EQ(3U, cookies.size());
3011 EXPECT_EQ(3U, removes.size());
3013 EXPECT_EQ("abc", cookies[1].Name());
3014 EXPECT_EQ("def", cookies[1].Value());
3015 EXPECT_TRUE(removes[1]);
3017 EXPECT_EQ("abc", cookies[2].Name());
3018 EXPECT_EQ("ghi", cookies[2].Value());
3019 EXPECT_FALSE(removes[2]);
3022 TEST_F(CookieMonsterNotificationTest, MultipleNotifies) {
3023 std::vector<CanonicalCookie> cookies0;
3024 std::vector<CanonicalCookie> cookies1;
3025 scoped_ptr<CookieStore::CookieChangedSubscription> sub0(
3026 monster()->AddCallbackForCookie(
3027 test_url_, "abc",
3028 base::Bind(&RecordCookieChanges, &cookies0, nullptr)));
3029 scoped_ptr<CookieStore::CookieChangedSubscription> sub1(
3030 monster()->AddCallbackForCookie(
3031 test_url_, "def",
3032 base::Bind(&RecordCookieChanges, &cookies1, nullptr)));
3033 SetCookie(monster(), test_url_, "abc=def");
3034 base::MessageLoop::current()->RunUntilIdle();
3035 EXPECT_EQ(1U, cookies0.size());
3036 EXPECT_EQ(0U, cookies1.size());
3037 SetCookie(monster(), test_url_, "def=abc");
3038 base::MessageLoop::current()->RunUntilIdle();
3039 EXPECT_EQ(1U, cookies0.size());
3040 EXPECT_EQ(1U, cookies1.size());
3043 TEST_F(CookieMonsterNotificationTest, MultipleSameNotifies) {
3044 std::vector<CanonicalCookie> cookies0;
3045 std::vector<CanonicalCookie> cookies1;
3046 scoped_ptr<CookieStore::CookieChangedSubscription> sub0(
3047 monster()->AddCallbackForCookie(
3048 test_url_, "abc",
3049 base::Bind(&RecordCookieChanges, &cookies0, nullptr)));
3050 scoped_ptr<CookieStore::CookieChangedSubscription> sub1(
3051 monster()->AddCallbackForCookie(
3052 test_url_, "abc",
3053 base::Bind(&RecordCookieChanges, &cookies1, nullptr)));
3054 SetCookie(monster(), test_url_, "abc=def");
3055 base::MessageLoop::current()->RunUntilIdle();
3056 EXPECT_EQ(1U, cookies0.size());
3057 EXPECT_EQ(1U, cookies0.size());
3060 } // namespace net