// 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. // This file contains test infrastructure for multiple files // (current cookie_monster_unittest.cc and cookie_monster_perftest.cc) // that need to test out CookieMonster interactions with the backing store. // It should only be included by test code. #include "base/time.h" #include "net/base/cookie_monster.h" #include "testing/gtest/include/gtest/gtest.h" namespace { // Describes a call to one of the 3 functions of PersistentCookieStore. struct CookieStoreCommand { enum Type { ADD, UPDATE_ACCESS_TIME, REMOVE, }; CookieStoreCommand(Type type, const net::CookieMonster::CanonicalCookie& cookie) : type(type), cookie(cookie) {} Type type; 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 CommandList; MockPersistentCookieStore() : load_return_value_(true) { } virtual bool Load( std::vector* out_cookies) { bool ok = load_return_value_; if (ok) *out_cookies = load_result_; return ok; } virtual void AddCookie(const net::CookieMonster::CanonicalCookie& cookie) { commands_.push_back( CookieStoreCommand(CookieStoreCommand::ADD, cookie)); } virtual void UpdateCookieAccessTime( const net::CookieMonster::CanonicalCookie& cookie) { commands_.push_back(CookieStoreCommand( CookieStoreCommand::UPDATE_ACCESS_TIME, cookie)); } virtual void DeleteCookie( const net::CookieMonster::CanonicalCookie& cookie) { commands_.push_back( CookieStoreCommand(CookieStoreCommand::REMOVE, cookie)); } void SetLoadExpectation( bool return_value, const std::vector& 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 load_result_; DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore); }; // Mock for CookieMonster::Delegate class MockCookieMonsterDelegate : public net::CookieMonster::Delegate { public: typedef std::pair CookieNotification; MockCookieMonsterDelegate() {} virtual void OnCookieChanged( const net::CookieMonster::CanonicalCookie& cookie, bool removed) { CookieNotification notification(cookie, removed); changes_.push_back(notification); } const std::vector& changes() const { return changes_; } void reset() { changes_.clear(); } private: virtual ~MockCookieMonsterDelegate() {} std::vector changes_; DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate); }; // Helper to build a list of CanonicalCookie*s. static void AddCookieToList( const std::string& key, const std::string& cookie_line, const base::Time& creation_time, std::vector* 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()); base::Time cookie_expires = pc.HasExpires() ? net::CookieMonster::ParseCookieTime(pc.Expires()) : base::Time(); std::string cookie_path = pc.Path(); scoped_ptr 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(cookie.release()); } // Just act like a backing database. Keep cookie information from // Add/Update/Delete and regurgitate it when Load is called. class MockSimplePersistentCookieStore : public net::CookieMonster::PersistentCookieStore { private: typedef std::map CanonicalCookieMap; public: virtual bool Load( std::vector* out_cookies) { for (CanonicalCookieMap::const_iterator it = cookies_.begin(); it != cookies_.end(); it++) out_cookies->push_back( new net::CookieMonster::CanonicalCookie(it->second)); return true; } virtual void AddCookie( const net::CookieMonster::CanonicalCookie& cookie) { int64 creation_time = cookie.CreationDate().ToInternalValue(); EXPECT_TRUE(cookies_.find(creation_time) == cookies_.end()); cookies_[creation_time] = cookie; } virtual void UpdateCookieAccessTime( const net::CookieMonster::CanonicalCookie& cookie) { int64 creation_time = cookie.CreationDate().ToInternalValue(); ASSERT_TRUE(cookies_.find(creation_time) != cookies_.end()); cookies_[creation_time].SetLastAccessDate(base::Time::Now()); } virtual void DeleteCookie( const net::CookieMonster::CanonicalCookie& cookie) { int64 creation_time = cookie.CreationDate().ToInternalValue(); CanonicalCookieMap::iterator it = cookies_.find(creation_time); ASSERT_TRUE(it != cookies_.end()); cookies_.erase(it); } private: CanonicalCookieMap cookies_; }; // Helper function for creating a CookieMonster backed by a // MockSimplePersistentCookieStore for garbage collection testing. // // Fill the store through import with |num_cookies| cookies, |num_old_cookies| // with access time Now()-days_old, the rest with access time Now(). // Do two SetCookies(). Return whether each of the two SetCookies() took // longer than |gc_perf_micros| to complete, and how many cookie were // left in the store afterwards. static net::CookieMonster* CreateMonsterFromStoreForGC( int num_cookies, int num_old_cookies, int days_old) { base::Time current(base::Time::Now()); base::Time past_creation(base::Time::Now() - base::TimeDelta::FromDays(1000)); scoped_refptr store( new MockSimplePersistentCookieStore); // Must expire to be persistent for (int i = 0; i < num_old_cookies; i++) { net::CookieMonster::CanonicalCookie cc( "a", "1", StringPrintf("h%05d.izzle", i), "/path", false, false, past_creation + base::TimeDelta::FromMicroseconds(i), current - base::TimeDelta::FromDays(days_old), true, current + base::TimeDelta::FromDays(30)); store->AddCookie(cc); } for (int i = num_old_cookies; i < num_cookies; i++) { net::CookieMonster::CanonicalCookie cc( "a", "1", StringPrintf("h%05d.izzle", i), "/path", false, false, past_creation + base::TimeDelta::FromMicroseconds(i), current, true, current + base::TimeDelta::FromDays(30)); store->AddCookie(cc); } return new net::CookieMonster(store, NULL); } } // namespace