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