| Index: net/base/cookie_monster_unittest.cc
|
| diff --git a/net/base/cookie_monster_unittest.cc b/net/base/cookie_monster_unittest.cc
|
| old mode 100644
|
| new mode 100755
|
| index c61a7821d37292d4775da6bcd58a0ea488827100..39bfbf551ff18ad4fae73800d3e6c938cafdc130
|
| --- a/net/base/cookie_monster_unittest.cc
|
| +++ b/net/base/cookie_monster_unittest.cc
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2010 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.
|
|
|
| @@ -14,8 +14,11 @@
|
| #include "base/time.h"
|
| #include "googleurl/src/gurl.h"
|
| #include "net/base/cookie_monster.h"
|
| +#include "net/base/cookie_monster_store_test.h" // For CookieStore Mock
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| +namespace net {
|
| +
|
| using base::Time;
|
| using base::TimeDelta;
|
|
|
| @@ -24,142 +27,6 @@ namespace {
|
| class ParsedCookieTest : public testing::Test { };
|
| class CookieMonsterTest : public testing::Test { };
|
|
|
| -// Describes a call to one of the 3 functions of PersistentCookieStore.
|
| -struct CookieStoreCommand {
|
| - enum Type {
|
| - ADD,
|
| - UPDATE_ACCESS_TIME,
|
| - REMOVE,
|
| - };
|
| -
|
| - CookieStoreCommand(Type type,
|
| - const std::string& key,
|
| - const net::CookieMonster::CanonicalCookie& cookie)
|
| - : type(type), key(key), cookie(cookie) {}
|
| -
|
| - Type type;
|
| - std::string key; // Only applicable to the ADD command.
|
| - net::CookieMonster::CanonicalCookie cookie;
|
| -};
|
| -
|
| -// Implementation of PersistentCookieStore that captures the
|
| -// received commands and saves them to a list.
|
| -// The result of calls to Load() can be configured using SetLoadExpectation().
|
| -class MockPersistentCookieStore
|
| - : public net::CookieMonster::PersistentCookieStore {
|
| - public:
|
| - typedef std::vector<CookieStoreCommand> CommandList;
|
| -
|
| - MockPersistentCookieStore() : load_return_value_(true) {
|
| - }
|
| -
|
| - virtual bool Load(
|
| - std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_cookies) {
|
| - bool ok = load_return_value_;
|
| - if (ok)
|
| - *out_cookies = load_result_;
|
| - return ok;
|
| - }
|
| -
|
| - virtual void AddCookie(const std::string& key,
|
| - const net::CookieMonster::CanonicalCookie& cookie) {
|
| - commands_.push_back(
|
| - CookieStoreCommand(CookieStoreCommand::ADD, key, cookie));
|
| - }
|
| -
|
| - virtual void UpdateCookieAccessTime(
|
| - const net::CookieMonster::CanonicalCookie& cookie) {
|
| - commands_.push_back(CookieStoreCommand(
|
| - CookieStoreCommand::UPDATE_ACCESS_TIME, std::string(), cookie));
|
| - }
|
| -
|
| - virtual void DeleteCookie(
|
| - const net::CookieMonster::CanonicalCookie& cookie) {
|
| - commands_.push_back(
|
| - CookieStoreCommand(CookieStoreCommand::REMOVE, std::string(), cookie));
|
| - }
|
| -
|
| - void SetLoadExpectation(
|
| - bool return_value,
|
| - const std::vector<net::CookieMonster::KeyedCanonicalCookie>& result) {
|
| - load_return_value_ = return_value;
|
| - load_result_ = result;
|
| - }
|
| -
|
| - const CommandList& commands() const {
|
| - return commands_;
|
| - }
|
| -
|
| - private:
|
| - CommandList commands_;
|
| -
|
| - // Deferred result to use when Load() is called.
|
| - bool load_return_value_;
|
| - std::vector<net::CookieMonster::KeyedCanonicalCookie> load_result_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore);
|
| -};
|
| -
|
| -// Mock for CookieMonster::Delegate
|
| -class MockCookieMonsterDelegate : public net::CookieMonster::Delegate {
|
| - public:
|
| - typedef std::pair<net::CookieMonster::CanonicalCookie, bool>
|
| - CookieNotification;
|
| -
|
| - MockCookieMonsterDelegate() {}
|
| -
|
| - virtual void OnCookieChanged(
|
| - const net::CookieMonster::CanonicalCookie& cookie,
|
| - bool removed) {
|
| - CookieNotification notification(cookie, removed);
|
| - changes_.push_back(notification);
|
| - }
|
| -
|
| - const std::vector<CookieNotification>& changes() const { return changes_; }
|
| -
|
| - void reset() { changes_.clear(); }
|
| -
|
| - private:
|
| - virtual ~MockCookieMonsterDelegate() {}
|
| -
|
| - std::vector<CookieNotification> changes_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate);
|
| -};
|
| -
|
| -// Helper to build a list of KeyedCanonicalCookies.
|
| -void AddKeyedCookieToList(
|
| - const std::string& key,
|
| - const std::string& cookie_line,
|
| - const Time& creation_time,
|
| - std::vector<net::CookieMonster::KeyedCanonicalCookie>* out_list) {
|
| -
|
| - // Parse the cookie line.
|
| - net::CookieMonster::ParsedCookie pc(cookie_line);
|
| - EXPECT_TRUE(pc.IsValid());
|
| -
|
| - // This helper is simplistic in interpreting a parsed cookie, in order to
|
| - // avoid duplicated CookieMonster's CanonPath() and CanonExpiration()
|
| - // functions. Would be nice to export them, and re-use here.
|
| - EXPECT_FALSE(pc.HasMaxAge());
|
| - EXPECT_TRUE(pc.HasPath());
|
| - Time cookie_expires = pc.HasExpires() ?
|
| - net::CookieMonster::ParseCookieTime(pc.Expires()) : Time();
|
| - std::string cookie_path = pc.Path();
|
| -
|
| - scoped_ptr<net::CookieMonster::CanonicalCookie> cookie(
|
| - new net::CookieMonster::CanonicalCookie(
|
| - pc.Name(), pc.Value(), key, cookie_path,
|
| - pc.IsSecure(), pc.IsHttpOnly(),
|
| - creation_time, creation_time,
|
| - !cookie_expires.is_null(),
|
| - cookie_expires));
|
| -
|
| - out_list->push_back(
|
| - net::CookieMonster::KeyedCanonicalCookie(
|
| - key, cookie.release()));
|
| -}
|
| -
|
| // Helper for DeleteAllForHost test; repopulates CM with same layout
|
| // each time.
|
| const char* kTopLevelDomainPlus1 = "http://www.harvard.edu";
|
| @@ -247,7 +114,6 @@ void PopulateCmForDeleteAllForHost(scoped_refptr<net::CookieMonster> cm) {
|
|
|
| } // namespace
|
|
|
| -
|
| TEST(ParsedCookieTest, TestBasic) {
|
| net::CookieMonster::ParsedCookie pc("a=b");
|
| EXPECT_TRUE(pc.IsValid());
|
| @@ -1490,7 +1356,10 @@ TEST(CookieMonsterTest, DontImportDuplicateCookies) {
|
| new MockPersistentCookieStore);
|
|
|
| // We will fill some initial cookies into the PersistentCookieStore,
|
| - // to simulate a database with 4 duplicates.
|
| + // to simulate a database with 4 duplicates. Note that we need to
|
| + // be careful not to have any duplicate creation times at all (as it's a
|
| + // violation of a CookieMonster invariant) even if Time::Now() doesn't
|
| + // move between calls.
|
| std::vector<net::CookieMonster::KeyedCanonicalCookie> initial_cookies;
|
|
|
| // Insert 4 cookies with name "X" on path "/", with varying creation
|
| @@ -1529,13 +1398,13 @@ TEST(CookieMonsterTest, DontImportDuplicateCookies) {
|
|
|
| AddKeyedCookieToList("www.google.com",
|
| "X=a2; path=/2; expires=Mon, 18-Apr-22 22:50:14 GMT",
|
| - Time::Now() + TimeDelta::FromDays(1),
|
| + Time::Now() + TimeDelta::FromDays(2),
|
| &initial_cookies);
|
|
|
| // Insert 1 cookie with name "Y" on path "/".
|
| AddKeyedCookieToList("www.google.com",
|
| "Y=a; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
|
| - Time::Now() + TimeDelta::FromDays(9),
|
| + Time::Now() + TimeDelta::FromDays(10),
|
| &initial_cookies);
|
|
|
| // Inject our initial cookies into the mock PersistentCookieStore.
|
| @@ -1560,6 +1429,74 @@ TEST(CookieMonsterTest, DontImportDuplicateCookies) {
|
| EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
|
| }
|
|
|
| +// Tests importing from a persistent cookie store that contains cookies
|
| +// with duplicate creation times. This situation should be handled by
|
| +// dropping the cookies before insertion/visibility to user.
|
| +//
|
| +// This is a regression test for: http://crbug.com/43188.
|
| +TEST(CookieMonsterTest, DontImportDuplicateCreationTimes) {
|
| + GURL url_google("http://www.google.com/");
|
| +
|
| + scoped_refptr<MockPersistentCookieStore> store(
|
| + new MockPersistentCookieStore);
|
| +
|
| + Time now(Time::Now());
|
| + Time earlier(now - TimeDelta::FromDays(1));
|
| +
|
| + // Insert 8 cookies, four with the current time as creation times, and
|
| + // four with the earlier time as creation times. We should only get
|
| + // two cookies remaining, but which two (other than that there should
|
| + // be one from each set) will be random.
|
| + std::vector<net::CookieMonster::KeyedCanonicalCookie> initial_cookies;
|
| + AddKeyedCookieToList("www.google.com",
|
| + "X=1; path=/",
|
| + now,
|
| + &initial_cookies);
|
| + AddKeyedCookieToList("www.google.com",
|
| + "X=2; path=/",
|
| + now,
|
| + &initial_cookies);
|
| + AddKeyedCookieToList("www.google.com",
|
| + "X=3; path=/",
|
| + now,
|
| + &initial_cookies);
|
| + AddKeyedCookieToList("www.google.com",
|
| + "X=4; path=/",
|
| + now,
|
| + &initial_cookies);
|
| +
|
| + AddKeyedCookieToList("www.google.com",
|
| + "Y=1; path=/",
|
| + earlier,
|
| + &initial_cookies);
|
| + AddKeyedCookieToList("www.google.com",
|
| + "Y=2; path=/",
|
| + earlier,
|
| + &initial_cookies);
|
| + AddKeyedCookieToList("www.google.com",
|
| + "Y=3; path=/",
|
| + earlier,
|
| + &initial_cookies);
|
| + AddKeyedCookieToList("www.google.com",
|
| + "Y=4; path=/",
|
| + earlier,
|
| + &initial_cookies);
|
| +
|
| + // Inject our initial cookies into the mock PersistentCookieStore.
|
| + store->SetLoadExpectation(true, initial_cookies);
|
| +
|
| + scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(store, NULL));
|
| +
|
| + net::CookieMonster::CookieList list(cm->GetAllCookies());
|
| + EXPECT_EQ(2U, list.size());
|
| + // Confirm that we have one of each.
|
| + std::string name1(list[0].Name());
|
| + std::string name2(list[1].Name());
|
| + EXPECT_TRUE(name1 == "X" || name2 == "X");
|
| + EXPECT_TRUE(name1 == "Y" || name2 == "Y");
|
| + EXPECT_NE(name1, name2);
|
| +}
|
| +
|
| TEST(CookieMonsterTest, Delegate) {
|
| GURL url_google(kUrlGoogle);
|
|
|
| @@ -1715,8 +1652,6 @@ TEST(CookieMonsterTest, SetCookieWithDetails) {
|
| ASSERT_TRUE(++it == cookies.end());
|
| }
|
|
|
| -
|
| -
|
| TEST(CookieMonsterTest, DeleteAllForHost) {
|
| scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
|
|
|
| @@ -1779,3 +1714,75 @@ TEST(CookieMonsterTest, DeleteAllForHost) {
|
| std::string("/dir1/dir2/xxx"))));
|
|
|
| }
|
| +
|
| +TEST(CookieMonsterTest, UniqueCreationTime) {
|
| + scoped_refptr<net::CookieMonster> cm(new net::CookieMonster(NULL, NULL));
|
| + GURL url_google(kUrlGoogle);
|
| + net::CookieOptions options;
|
| +
|
| + // Add in three cookies through every public interface to the
|
| + // CookieMonster and confirm that none of them have duplicate
|
| + // creation times.
|
| +
|
| + // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
|
| + // are not included as they aren't going to be public for very much
|
| + // longer.
|
| +
|
| + // SetCookie, SetCookies, SetCookiesWithOptions,
|
| + // SetCookieWithOptions, SetCookieWithDetails
|
| +
|
| + cm->SetCookie(url_google, "SetCookie1=A");
|
| + cm->SetCookie(url_google, "SetCookie2=A");
|
| + cm->SetCookie(url_google, "SetCookie3=A");
|
| +
|
| + {
|
| + std::vector<std::string> cookie_lines;
|
| + cookie_lines.push_back("setCookies1=A");
|
| + cookie_lines.push_back("setCookies2=A");
|
| + cookie_lines.push_back("setCookies4=A");
|
| + cm->SetCookies(url_google, cookie_lines);
|
| + }
|
| +
|
| + {
|
| + std::vector<std::string> cookie_lines;
|
| + cookie_lines.push_back("setCookiesWithOptions1=A");
|
| + cookie_lines.push_back("setCookiesWithOptions2=A");
|
| + cookie_lines.push_back("setCookiesWithOptions3=A");
|
| +
|
| + cm->SetCookiesWithOptions(url_google, cookie_lines, options);
|
| + }
|
| +
|
| + cm->SetCookieWithOptions(url_google, "setCookieWithOptions1=A", options);
|
| + cm->SetCookieWithOptions(url_google, "setCookieWithOptions2=A", options);
|
| + cm->SetCookieWithOptions(url_google, "setCookieWithOptions3=A", options);
|
| +
|
| + cm->SetCookieWithDetails(url_google, "setCookieWithDetails1", "A",
|
| + ".google.com", "/", Time(), false, false);
|
| + cm->SetCookieWithDetails(url_google, "setCookieWithDetails2", "A",
|
| + ".google.com", "/", Time(), false, false);
|
| + cm->SetCookieWithDetails(url_google, "setCookieWithDetails3", "A",
|
| + ".google.com", "/", Time(), false, false);
|
| +
|
| + // Now we check
|
| + net::CookieMonster::CookieList cookie_list(cm->GetAllCookies());
|
| + typedef std::map<int64, net::CookieMonster::CanonicalCookie> TimeCookieMap;
|
| + TimeCookieMap check_map;
|
| + for (net::CookieMonster::CookieList::const_iterator it = cookie_list.begin();
|
| + it != cookie_list.end(); it++) {
|
| + const int64 creation_date = it->CreationDate().ToInternalValue();
|
| + TimeCookieMap::const_iterator
|
| + existing_cookie_it(check_map.find(creation_date));
|
| + EXPECT_TRUE(existing_cookie_it == check_map.end())
|
| + << "Cookie " << it->Name() << " has same creation date ("
|
| + << it->CreationDate().ToInternalValue()
|
| + << ") as previously entered cookie "
|
| + << existing_cookie_it->second.Name();
|
| +
|
| + if (existing_cookie_it == check_map.end()) {
|
| + check_map.insert(TimeCookieMap::value_type(
|
| + it->CreationDate().ToInternalValue(), *it));
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
|
|