diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-15 09:29:58 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-15 09:29:58 +0000 |
commit | 63ee33bde2ec8471a70f0f0ec6a1962dd07fc8ab (patch) | |
tree | 7c38150e4b53fa60235d4d3845100d805ba85d35 /net/cookies/cookie_store_unittest.h | |
parent | ca2fd075cf4eaeb2ee650affff606bbb3120772c (diff) | |
download | chromium_src-63ee33bde2ec8471a70f0f0ec6a1962dd07fc8ab.zip chromium_src-63ee33bde2ec8471a70f0f0ec6a1962dd07fc8ab.tar.gz chromium_src-63ee33bde2ec8471a70f0f0ec6a1962dd07fc8ab.tar.bz2 |
Move the cookie store implementation into its own directory.
In the initial step, forwarding headers are left in net/base/cookie_*h . After all clients are updated these will be removed and erikwright will be removed from net/base/OWNERS
BUG=70818
TEST=compilation
Review URL: http://codereview.chromium.org/9703011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126871 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/cookies/cookie_store_unittest.h')
-rw-r--r-- | net/cookies/cookie_store_unittest.h | 1055 |
1 files changed, 1055 insertions, 0 deletions
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h new file mode 100644 index 0000000..e1d23f8 --- /dev/null +++ b/net/cookies/cookie_store_unittest.h @@ -0,0 +1,1055 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_COOKIES_COOKIE_STORE_UNITTEST_H_ +#define NET_COOKIES_COOKIE_STORE_UNITTEST_H_ +#pragma once + +#include "base/bind.h" +#include "base/message_loop.h" +#include "base/string_tokenizer.h" +#include "base/threading/thread.h" +#include "googleurl/src/gurl.h" +#include "net/cookies/cookie_monster.h" +#include "net/cookies/cookie_store.h" +#include "net/cookies/cookie_store_test_callbacks.h" +#include "testing/gtest/include/gtest/gtest.h" + +// This file declares unittest templates that can be used to test common +// behavior of any CookieStore implementation. +// See cookie_monster_unittest.cc for an example of an implementation. + +namespace net { + +using base::Thread; + +const int kTimeout = 1000; + +const char kUrlFtp[] = "ftp://ftp.google.izzle/"; +const char kUrlGoogle[] = "http://www.google.izzle"; +const char kUrlGoogleFoo[] = "http://www.google.izzle/foo"; +const char kUrlGoogleBar[] = "http://www.google.izzle/bar"; +const char kUrlGoogleSecure[] = "https://www.google.izzle"; +const char kValidCookieLine[] = "A=B; path=/"; +const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle"; + +// The CookieStoreTestTraits must have the following members: +// struct CookieStoreTestTraits { +// // Factory function. +// static scoped_refptr<CookieStore> Create(); +// +// // The cookie store is a CookieMonster. Only used to test +// // GetCookieMonster(). +// static const bool is_cookie_monster; +// +// // The cookie store supports cookies with the exclude_httponly() option. +// static const bool supports_http_only; +// +// // The cookie store supports the GetCookiesWithInfoAsync() method. +// static const bool supports_cookies_with_info; +// +// // The cookie store is able to make the difference between the ".com" +// // and the "com" domains. +// static const bool supports_non_dotted_domains; +// +// // The cookie store handles the domains with trailing dots (such as "com.") +// // correctly. +// static const bool supports_trailing_dots; +// +// // The cookie store rejects cookies for invalid schemes such as ftp. +// static const bool filters_schemes; +// +// // The cookie store has a bug happening when a path is a substring of +// // another. +// static const bool has_path_prefix_bug; +// +// // Time to wait between two cookie insertions to ensure that cookies have +// // different creation times. +// static const int creation_time_granularity_in_ms; +// }; + +template <class CookieStoreTestTraits> +class CookieStoreTest : public testing::Test { + protected: + CookieStoreTest() + : url_google_(kUrlGoogle), + url_google_secure_(kUrlGoogleSecure), + url_google_foo_(kUrlGoogleFoo), + url_google_bar_(kUrlGoogleBar) { + // This test may be used outside of the net test suite, and thus may not + // have a message loop. + if (!MessageLoop::current()) + message_loop_.reset(new MessageLoop); + weak_factory_.reset( + new base::WeakPtrFactory<MessageLoop>(MessageLoop::current())); + } + + // Helper methods for the asynchronous Cookie Store API that call the + // asynchronous method and then pump the loop until the callback is invoked, + // finally returning the value. + + std::string GetCookies(CookieStore* cs, const GURL& url) { + DCHECK(cs); + CookieOptions options; + if (!CookieStoreTestTraits::supports_http_only) + options.set_include_httponly(); + GetCookieStringCallback callback; + cs->GetCookiesWithOptionsAsync( + url, options, + base::Bind(&GetCookieStringCallback::Run, base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + return callback.cookie(); + } + + std::string GetCookiesWithOptions(CookieStore* cs, + const GURL& url, + const CookieOptions& options) { + DCHECK(cs); + GetCookieStringCallback callback; + cs->GetCookiesWithOptionsAsync( + url, options, base::Bind(&GetCookieStringCallback::Run, + base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + return callback.cookie(); + } + + void GetCookiesWithInfo(CookieStore* cs, + const GURL& url, + const CookieOptions& options, + std::string* cookie_line, + std::vector<CookieStore::CookieInfo>* cookie_info) { + DCHECK(cs); + DCHECK(cookie_line); + DCHECK(cookie_info); + GetCookiesWithInfoCallback callback; + cs->GetCookiesWithInfoAsync( + url, options, base::Bind(&GetCookiesWithInfoCallback::Run, + base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + *cookie_line = callback.cookie_line(); + *cookie_info = callback.cookie_info(); + } + + bool SetCookieWithOptions(CookieStore* cs, + const GURL& url, + const std::string& cookie_line, + const CookieOptions& options) { + DCHECK(cs); + SetCookieCallback callback; + cs->SetCookieWithOptionsAsync( + url, cookie_line, options, + base::Bind(&SetCookieCallback::Run, base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + return callback.result(); + } + + bool SetCookie(CookieStore* cs, + const GURL& url, + const std::string& cookie_line) { + CookieOptions options; + if (!CookieStoreTestTraits::supports_http_only) + options.set_include_httponly(); + return SetCookieWithOptions(cs, url, cookie_line, options); + } + + void DeleteCookie(CookieStore* cs, + const GURL& url, + const std::string& cookie_name) { + DCHECK(cs); + DeleteCookieCallback callback; + cs->DeleteCookieAsync( + url, cookie_name, + base::Bind(&DeleteCookieCallback::Run, base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + } + + int DeleteCreatedBetween(CookieStore* cs, + const base::Time& delete_begin, + const base::Time& delete_end) { + DCHECK(cs); + DeleteCallback callback; + cs->DeleteAllCreatedBetweenAsync( + delete_begin, delete_end, + base::Bind(&DeleteCallback::Run, base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + return callback.num_deleted(); + } + + void RunFor(int ms) { + // Runs the test thread message loop for up to |ms| milliseconds. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, base::Bind(&MessageLoop::Quit, weak_factory_->GetWeakPtr()), + base::TimeDelta::FromMilliseconds(ms)); + MessageLoop::current()->Run(); + weak_factory_->InvalidateWeakPtrs(); + } + + scoped_refptr<CookieStore> GetCookieStore() { + return CookieStoreTestTraits::Create(); + } + + // Compares two cookie lines. + void MatchCookieLines(const std::string& line1, const std::string& line2) { + EXPECT_EQ(TokenizeCookieLine(line1), TokenizeCookieLine(line2)); + } + + // Check the cookie line by polling until equality or a timeout is reached. + void MatchCookieLineWithTimeout(CookieStore* cs, + const GURL& url, + const std::string& line) { + std::string cookies = GetCookies(cs, url); + bool matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); + base::Time polling_end_date = base::Time::Now() + + base::TimeDelta::FromMilliseconds( + CookieStoreTestTraits::creation_time_granularity_in_ms); + + while (!matched && base::Time::Now() <= polling_end_date) { + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); + cookies = GetCookies(cs, url); + matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); + } + + EXPECT_TRUE(matched) << "\"" << cookies + << "\" does not match \"" << line << "\""; + } + + GURL url_google_; + GURL url_google_secure_; + GURL url_google_foo_; + GURL url_google_bar_; + + scoped_ptr<base::WeakPtrFactory<MessageLoop> > weak_factory_; + scoped_ptr<MessageLoop> message_loop_; + + private: + // Returns a set of strings of type "name=value". Fails in case of duplicate. + std::set<std::string> TokenizeCookieLine(const std::string& line) { + std::set<std::string> tokens; + StringTokenizer tokenizer(line, " ;"); + while (tokenizer.GetNext()) + EXPECT_TRUE(tokens.insert(tokenizer.token()).second); + return tokens; + } +}; + +TYPED_TEST_CASE_P(CookieStoreTest); + +TYPED_TEST_P(CookieStoreTest, TypeTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_EQ(cs->GetCookieMonster(), + (TypeParam::is_cookie_monster) ? + static_cast<CookieMonster*>(cs.get()) : NULL); +} + +TYPED_TEST_P(CookieStoreTest, DomainTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + "C=D; domain=.google.izzle")); + this->MatchCookieLines("A=B; C=D", this->GetCookies(cs, this->url_google_)); + + // Verify that A=B was set as a host cookie rather than a domain + // cookie -- should not be accessible from a sub sub-domain. + this->MatchCookieLines("C=D", + this->GetCookies(cs, GURL("http://foo.www.google.izzle"))); + + // Test and make sure we find domain cookies on the same domain. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + "E=F; domain=.www.google.izzle")); + this->MatchCookieLines("A=B; C=D; E=F", + this->GetCookies(cs, this->url_google_)); + + // Test setting a domain= that doesn't start w/ a dot, should + // treat it as a domain cookie, as if there was a pre-pended dot. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + "G=H; domain=www.google.izzle")); + this->MatchCookieLines("A=B; C=D; E=F; G=H", + this->GetCookies(cs, this->url_google_)); + + // Test domain enforcement, should fail on a sub-domain or something too deep. + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "I=J; domain=.izzle")); + this->MatchCookieLines("", this->GetCookies(cs, GURL("http://a.izzle"))); + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, + "K=L; domain=.bla.www.google.izzle")); + this->MatchCookieLines("C=D; E=F; G=H", + this->GetCookies(cs, GURL("http://bla.www.google.izzle"))); + this->MatchCookieLines("A=B; C=D; E=F; G=H", + this->GetCookies(cs, this->url_google_)); +} + +// FireFox recognizes domains containing trailing periods as valid. +// IE and Safari do not. Assert the expected policy here. +TYPED_TEST_P(CookieStoreTest, DomainWithTrailingDotTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, + "a=1; domain=.www.google.com.")); + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, + "b=2; domain=.www.google.com..")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); +} + +// Test that cookies can bet set on higher level domains. +// http://b/issue?id=896491 +TYPED_TEST_P(CookieStoreTest, ValidSubdomainTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_abcd("http://a.b.c.d.com"); + GURL url_bcd("http://b.c.d.com"); + GURL url_cd("http://c.d.com"); + GURL url_d("http://d.com"); + + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "a=1; domain=.a.b.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "b=2; domain=.b.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "c=3; domain=.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "d=4; domain=.d.com")); + + this->MatchCookieLines("a=1; b=2; c=3; d=4", this->GetCookies(cs, url_abcd)); + this->MatchCookieLines("b=2; c=3; d=4", this->GetCookies(cs, url_bcd)); + this->MatchCookieLines("c=3; d=4", this->GetCookies(cs, url_cd)); + this->MatchCookieLines("d=4", this->GetCookies(cs, url_d)); + + // Check that the same cookie can exist on different sub-domains. + EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=bcd; domain=.b.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=cd; domain=.c.d.com")); + this->MatchCookieLines("b=2; c=3; d=4; X=bcd; X=cd", + this->GetCookies(cs, url_bcd)); + this->MatchCookieLines("c=3; d=4; X=cd", this->GetCookies(cs, url_cd)); +} + +// Test that setting a cookie which specifies an invalid domain has +// no side-effect. An invalid domain in this context is one which does +// not match the originating domain. +// http://b/issue?id=896472 +TYPED_TEST_P(CookieStoreTest, InvalidDomainTest) { + { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_foobar("http://foo.bar.com"); + + // More specific sub-domain than allowed. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "a=1; domain=.yo.foo.bar.com")); + + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "b=2; domain=.foo.com")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "c=3; domain=.bar.foo.com")); + + // Different TLD, but the rest is a substring. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "d=4; domain=.foo.bar.com.net")); + + // A substring that isn't really a parent domain. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "e=5; domain=ar.com")); + + // Completely invalid domains: + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "f=6; domain=.")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "g=7; domain=/")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "h=8; domain=http://foo.bar.com")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "i=9; domain=..foo.bar.com")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "j=10; domain=..bar.com")); + + // Make sure there isn't something quirky in the domain canonicalization + // that supports full URL semantics. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "k=11; domain=.foo.bar.com?blah")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "l=12; domain=.foo.bar.com/blah")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "m=13; domain=.foo.bar.com:80")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "n=14; domain=.foo.bar.com:")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "o=15; domain=.foo.bar.com#sup")); + + this->MatchCookieLines("", this->GetCookies(cs, url_foobar)); + } + + { + // Make sure the cookie code hasn't gotten its subdomain string handling + // reversed, missed a suffix check, etc. It's important here that the two + // hosts below have the same domain + registry. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_foocom("http://foo.com.com"); + EXPECT_FALSE(this->SetCookie(cs, url_foocom, + "a=1; domain=.foo.com.com.com")); + this->MatchCookieLines("", this->GetCookies(cs, url_foocom)); + } +} + +// Test the behavior of omitting dot prefix from domain, should +// function the same as FireFox. +// http://b/issue?id=889898 +TYPED_TEST_P(CookieStoreTest, DomainWithoutLeadingDotTest) { + { // The omission of dot results in setting a domain cookie. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_hosted("http://manage.hosted.filefront.com"); + GURL url_filefront("http://www.filefront.com"); + EXPECT_TRUE(this->SetCookie(cs, url_hosted, + "sawAd=1; domain=filefront.com")); + this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_hosted)); + this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_filefront)); + } + + { // Even when the domains match exactly, don't consider it host cookie. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://www.google.com"); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=www.google.com")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + this->MatchCookieLines("a=1", + this->GetCookies(cs, GURL("http://sub.www.google.com"))); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://something-else.com"))); + } +} + +// Test that the domain specified in cookie string is treated case-insensitive +// http://b/issue?id=896475. +TYPED_TEST_P(CookieStoreTest, CaseInsensitiveDomainTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://www.google.com"); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=.GOOGLE.COM")); + EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.wWw.gOOgLE.coM")); + this->MatchCookieLines("a=1; b=2", this->GetCookies(cs, url)); +} + +TYPED_TEST_P(CookieStoreTest, TestIpAddress) { + GURL url_ip("http://1.2.3.4/weee"); + { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, url_ip, kValidCookieLine)); + this->MatchCookieLines("A=B", this->GetCookies(cs, url_ip)); + } + + { // IP addresses should not be able to set domain cookies. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=.1.2.3.4")); + EXPECT_FALSE(this->SetCookie(cs, url_ip, "c=3; domain=.3.4")); + this->MatchCookieLines("", this->GetCookies(cs, url_ip)); + // It should be allowed to set a cookie if domain= matches the IP address + // exactly. This matches IE/Firefox, even though it seems a bit wrong. + EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.3")); + this->MatchCookieLines("", this->GetCookies(cs, url_ip)); + EXPECT_TRUE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.4")); + this->MatchCookieLines("b=2", this->GetCookies(cs, url_ip)); + } +} + +// Test host cookies, and setting of cookies on TLD. +TYPED_TEST_P(CookieStoreTest, TestNonDottedAndTLD) { + { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://com/"); + // Allow setting on "com", (but only as a host cookie). + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.com")); + EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=com")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + // Make sure it doesn't show up for a normal .com, it should be a host + // not a domain cookie. + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/"))); + if (TypeParam::supports_non_dotted_domains) { + this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/"))); + } + } + + { + // http://com. should be treated the same as http://com. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://com./index.html"); + if (TypeParam::supports_trailing_dots) { + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://hopefully-no-cookies.com./"))); + } else { + EXPECT_FALSE(this->SetCookie(cs, url, "a=1")); + } + } + + { // Should not be able to set host cookie from a subdomain. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://a.b"); + EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.b")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=b")); + this->MatchCookieLines("", this->GetCookies(cs, url)); + } + + { // Same test as above, but explicitly on a known TLD (com). + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://google.com"); + EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.com")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=com")); + this->MatchCookieLines("", this->GetCookies(cs, url)); + } + + { // Make sure can't set cookie on TLD which is dotted. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://google.co.uk"); + EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.co.uk")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.uk")); + this->MatchCookieLines("", this->GetCookies(cs, url)); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://something-else.co.uk"))); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://something-else.uk"))); + } + + { // Intranet URLs should only be able to set host cookies. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://b"); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.b")); + EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=b")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + } +} + +// Test reading/writing cookies when the domain ends with a period, +// as in "www.google.com." +TYPED_TEST_P(CookieStoreTest, TestHostEndsWithDot) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://www.google.com"); + GURL url_with_dot("http://www.google.com."); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + + if (TypeParam::supports_trailing_dots) { + // Do not share cookie space with the dot version of domain. + // Note: this is not what FireFox does, but it _is_ what IE+Safari do. + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.www.google.com.")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + + EXPECT_TRUE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com.")); + this->MatchCookieLines("b=2", this->GetCookies(cs, url_with_dot)); + } else { + EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.www.google.com.")); + EXPECT_FALSE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com.")); + } + + // Make sure there weren't any side effects. + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/"))); + this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/"))); +} + +TYPED_TEST_P(CookieStoreTest, InvalidScheme) { + if (!TypeParam::filters_schemes) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_FALSE(this->SetCookie(cs, GURL(kUrlFtp), kValidCookieLine)); +} + +TYPED_TEST_P(CookieStoreTest, InvalidScheme_Read) { + if (!TypeParam::filters_schemes) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, GURL(kUrlGoogle), kValidDomainCookieLine)); + this->MatchCookieLines("", this->GetCookies(cs, GURL(kUrlFtp))); +} + +TYPED_TEST_P(CookieStoreTest, PathTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + std::string url("http://www.google.izzle"); + EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=B; path=/wee")); + this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee"))); + this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/"))); + this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/war"))); + this->MatchCookieLines("A=B", + this->GetCookies(cs, GURL(url + "/wee/war/more/more"))); + if (!TypeParam::has_path_prefix_bug) + this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/weehee"))); + this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/"))); + + // If we add a 0 length path, it should default to / + EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=C; path=")); + this->MatchCookieLines("A=B; A=C", this->GetCookies(cs, GURL(url + "/wee"))); + this->MatchCookieLines("A=C", this->GetCookies(cs, GURL(url + "/"))); +} + +TYPED_TEST_P(CookieStoreTest, HttpOnlyTest) { + if (!TypeParam::supports_http_only) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + options.set_include_httponly(); + + // Create a httponly cookie. + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B; httponly", + options)); + + // Check httponly read protection. + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + + // Check httponly overwrite protection. + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "A=C")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=C", + options)); + this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_)); + + // Check httponly create protection. + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "B=A; httponly")); + this->MatchCookieLines("A=C", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "B=A; httponly", + options)); + this->MatchCookieLines("A=C; B=A", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_)); +} + +TYPED_TEST_P(CookieStoreTest, TestGetCookiesWithInfo) { + if (!TypeParam::supports_cookies_with_info) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, + "C=D; Mac-Key=390jfn0awf3; Mac-Algorithm=hmac-sha-1", options)); + + this->MatchCookieLines("A=B; C=D", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + + std::string cookie_line; + std::vector<CookieStore::CookieInfo> cookie_infos; + + this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line, + &cookie_infos); + + EXPECT_EQ("A=B; C=D", cookie_line); + + EXPECT_EQ(2U, cookie_infos.size()); + + EXPECT_EQ("A", cookie_infos[0].name); + EXPECT_EQ("", cookie_infos[0].mac_key); + EXPECT_EQ("", cookie_infos[0].mac_algorithm); + + EXPECT_EQ("C", cookie_infos[1].name); + EXPECT_EQ("390jfn0awf3", cookie_infos[1].mac_key); + EXPECT_EQ("hmac-sha-1", cookie_infos[1].mac_algorithm); +} + +TYPED_TEST_P(CookieStoreTest, TestCookieDeletion) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + // Create a session cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Max-Age. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + "; max-age=0")); + this->MatchCookieLineWithTimeout(cs, this->url_google_, ""); + + // Create a session cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Expires. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + + // Create a persistent cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); + + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Max-Age. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + "; max-age=0")); + this->MatchCookieLineWithTimeout(cs, this->url_google_, ""); + + // Create a persistent cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Expires. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + + // Create a persistent cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Expires, with a unix epoch of 0. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Thu, 1-Jan-1970 00:00:00 GMT")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); +} + +TYPED_TEST_P(CookieStoreTest, TestDeleteAllCreatedBetween) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + const base::Time last_month = base::Time::Now() - + base::TimeDelta::FromDays(30); + const base::Time last_minute = base::Time::Now() - + base::TimeDelta::FromMinutes(1); + const base::Time next_minute = base::Time::Now() + + base::TimeDelta::FromMinutes(1); + const base::Time next_month = base::Time::Now() + + base::TimeDelta::FromDays(30); + + // Add a cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + // Check that the cookie is in the store. + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + + // Remove cookies in empty intervals. + EXPECT_EQ(0, this->DeleteCreatedBetween(cs, last_month, last_minute)); + EXPECT_EQ(0, this->DeleteCreatedBetween(cs, next_minute, next_month)); + // Check that the cookie is still there. + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + + // Remove the cookie with an interval defined by two dates. + EXPECT_EQ(1, this->DeleteCreatedBetween(cs, last_minute, next_minute)); + // Check that the cookie disappeared. + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + + // Add another cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "C=D")); + // Check that the cookie is in the store. + this->MatchCookieLines("C=D", this->GetCookies(cs, this->url_google_)); + + // Remove the cookie with a null ending time. + EXPECT_EQ(1, this->DeleteCreatedBetween(cs, last_minute, base::Time())); + // Check that the cookie disappeared. + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); +} + +TYPED_TEST_P(CookieStoreTest, TestSecure) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_)); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B; secure")); + // The secure should overwrite the non-secure. + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_)); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "D=E; secure")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B; D=E", + this->GetCookies(cs, this->url_google_secure_)); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B")); + // The non-secure should overwrite the secure. + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("D=E; A=B", + this->GetCookies(cs, this->url_google_secure_)); +} + +static const int kLastAccessThresholdMilliseconds = 200; + +// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling. +TYPED_TEST_P(CookieStoreTest, NetUtilCookieTest) { + const GURL test_url("http://mojo.jojo.google.izzle/"); + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + EXPECT_TRUE(this->SetCookie(cs, test_url, "foo=bar")); + std::string value = this->GetCookies(cs, test_url); + this->MatchCookieLines("foo=bar", value); + + // test that we can retrieve all cookies: + EXPECT_TRUE(this->SetCookie(cs, test_url, "x=1")); + EXPECT_TRUE(this->SetCookie(cs, test_url, "y=2")); + + std::string result = this->GetCookies(cs, test_url); + EXPECT_FALSE(result.empty()); + EXPECT_NE(result.find("x=1"), std::string::npos) << result; + EXPECT_NE(result.find("y=2"), std::string::npos) << result; +} + +TYPED_TEST_P(CookieStoreTest, OverwritePersistentCookie) { + GURL url_google("http://www.google.com/"); + GURL url_chromium("http://chromium.org"); + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + // Insert a cookie "a" for path "/path1" + EXPECT_TRUE( + this->SetCookie(cs, url_google, "a=val1; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:13 GMT")); + + // Insert a cookie "b" for path "/path1" + EXPECT_TRUE( + this->SetCookie(cs, url_google, "b=val1; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + // Insert a cookie "b" for path "/path1", that is httponly. This should + // overwrite the non-http-only version. + CookieOptions allow_httponly; + allow_httponly.set_include_httponly(); + EXPECT_TRUE( + this->SetCookieWithOptions(cs, url_google, + "b=val2; path=/path1; httponly; " + "expires=Mon, 18-Apr-22 22:50:14 GMT", + allow_httponly)); + + // Insert a cookie "a" for path "/path1". This should overwrite. + EXPECT_TRUE(this->SetCookie(cs, url_google, + "a=val33; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + // Insert a cookie "a" for path "/path2". This should NOT overwrite + // cookie "a", since the path is different. + EXPECT_TRUE(this->SetCookie(cs, url_google, + "a=val9; path=/path2; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + // Insert a cookie "a" for path "/path1", but this time for "chromium.org". + // Although the name and path match, the hostnames do not, so shouldn't + // overwrite. + EXPECT_TRUE(this->SetCookie(cs, url_chromium, + "a=val99; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + if (TypeParam::supports_http_only) { + this->MatchCookieLines("a=val33", + this->GetCookies(cs, GURL("http://www.google.com/path1"))); + } else { + this->MatchCookieLines("a=val33; b=val2", + this->GetCookies(cs, GURL("http://www.google.com/path1"))); + } + this->MatchCookieLines("a=val9", + this->GetCookies(cs, GURL("http://www.google.com/path2"))); + this->MatchCookieLines("a=val99", + this->GetCookies(cs, GURL("http://chromium.org/path1"))); +} + +TYPED_TEST_P(CookieStoreTest, CookieOrdering) { + // Put a random set of cookies into a store and make sure they're returned in + // the right order. + // Cookies should be sorted by path length and creation time, as per RFC6265. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://d.c.b.a.google.com/aa/x.html"), + "c=1")); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"), + "d=1; domain=b.a.google.com")); + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds( + TypeParam::creation_time_granularity_in_ms)); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"), + "a=4; domain=b.a.google.com")); + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds( + TypeParam::creation_time_granularity_in_ms)); + EXPECT_TRUE(this->SetCookie(cs, + GURL("http://c.b.a.google.com/aa/bb/cc/x.html"), + "e=1; domain=c.b.a.google.com")); + EXPECT_TRUE(this->SetCookie(cs, + GURL("http://d.c.b.a.google.com/aa/bb/x.html"), + "b=1")); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://news.bbc.co.uk/midpath/x.html"), + "g=10")); + EXPECT_EQ("d=1; a=4; e=1; b=1; c=1", + this->GetCookies(cs, GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"))); +} + +REGISTER_TYPED_TEST_CASE_P(CookieStoreTest, + TypeTest, DomainTest, DomainWithTrailingDotTest, ValidSubdomainTest, + InvalidDomainTest, DomainWithoutLeadingDotTest, CaseInsensitiveDomainTest, + TestIpAddress, TestNonDottedAndTLD, TestHostEndsWithDot, InvalidScheme, + InvalidScheme_Read, PathTest, HttpOnlyTest, TestGetCookiesWithInfo, + TestCookieDeletion, TestDeleteAllCreatedBetween, TestSecure, + NetUtilCookieTest, OverwritePersistentCookie, CookieOrdering); + +template<class CookieStoreTestTraits> +class MultiThreadedCookieStoreTest : + public CookieStoreTest<CookieStoreTestTraits> { + public: + MultiThreadedCookieStoreTest() : other_thread_("CMTthread") {} + + // Helper methods for calling the asynchronous CookieStore methods + // from a different thread. + + void GetCookiesTask(CookieStore* cs, + const GURL& url, + GetCookieStringCallback* callback) { + CookieOptions options; + if (!CookieStoreTestTraits::supports_http_only) + options.set_include_httponly(); + cs->GetCookiesWithOptionsAsync( + url, options, + base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback))); + } + + void GetCookiesWithOptionsTask(CookieStore* cs, + const GURL& url, + const CookieOptions& options, + GetCookieStringCallback* callback) { + cs->GetCookiesWithOptionsAsync( + url, options, + base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback))); + } + + void GetCookiesWithInfoTask(CookieStore* cs, + const GURL& url, + const CookieOptions& options, + GetCookiesWithInfoCallback* callback) { + cs->GetCookiesWithInfoAsync( + url, options, + base::Bind(&GetCookiesWithInfoCallback::Run, + base::Unretained(callback))); + } + + void SetCookieWithOptionsTask(CookieStore* cs, + const GURL& url, + const std::string& cookie_line, + const CookieOptions& options, + SetCookieCallback* callback) { + cs->SetCookieWithOptionsAsync( + url, cookie_line, options, + base::Bind(&SetCookieCallback::Run, base::Unretained(callback))); + } + + void DeleteCookieTask(CookieStore* cs, + const GURL& url, + const std::string& cookie_name, + DeleteCookieCallback* callback) { + cs->DeleteCookieAsync( + url, cookie_name, + base::Bind(&DeleteCookieCallback::Run, base::Unretained(callback))); + } + + protected: + void RunOnOtherThread(const base::Closure& task) { + other_thread_.Start(); + other_thread_.message_loop()->PostTask(FROM_HERE, task); + CookieStoreTest<CookieStoreTestTraits>::RunFor(kTimeout); + other_thread_.Stop(); + } + + Thread other_thread_; +}; + +TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest); + +// TODO(ycxiao): Eventually, we will need to create a separate thread, create +// the cookie store on that thread (or at least its store, i.e., the DB +// thread). +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookies) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + GetCookieStringCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask, + base::Unretained(this), + cs, this->url_google_, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + EXPECT_EQ("A=B", callback.cookie()); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithOptions) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + if (!TypeParam::supports_http_only) + options.set_include_httponly(); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + GetCookieStringCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithOptionsTask, + base::Unretained(this), + cs, this->url_google_, options, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + EXPECT_EQ("A=B", callback.cookie()); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithInfo) { + if (!TypeParam::supports_cookies_with_info) + return; + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + std::string cookie_line; + std::vector<CookieStore::CookieInfo> cookie_infos; + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line, + &cookie_infos); + this->MatchCookieLines("A=B", cookie_line); + EXPECT_EQ(1U, cookie_infos.size()); + EXPECT_EQ("A", cookie_infos[0].name); + EXPECT_EQ("", cookie_infos[0].mac_key); + EXPECT_EQ("", cookie_infos[0].mac_algorithm); + GetCookiesWithInfoCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithInfoTask, + base::Unretained(this), cs, this->url_google_, options, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + this->MatchCookieLines("A=B", callback.cookie_line()); + EXPECT_EQ(1U, callback.cookie_info().size()); + EXPECT_EQ("A", callback.cookie_info()[0].name); + EXPECT_EQ("", callback.cookie_info()[0].mac_key); + EXPECT_EQ("", callback.cookie_info()[0].mac_algorithm); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckSetCookieWithOptions) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + if (!TypeParam::supports_http_only) + options.set_include_httponly(); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + SetCookieCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::SetCookieWithOptionsTask, + base::Unretained(this), + cs, this->url_google_, "A=B", options, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + EXPECT_TRUE(callback.result()); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckDeleteCookie) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + if (!TypeParam::supports_http_only) + options.set_include_httponly(); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + this->DeleteCookie(cs, this->url_google_, "A"); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + DeleteCookieCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask, + base::Unretained(this), + cs, this->url_google_, "A", &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); +} + +REGISTER_TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest, + ThreadCheckGetCookies, ThreadCheckGetCookiesWithOptions, + ThreadCheckGetCookiesWithInfo, ThreadCheckSetCookieWithOptions, + ThreadCheckDeleteCookie); + +} // namespace net + +#endif // NET_COOKIES_COOKIE_STORE_UNITTEST_H_ |