1 // Copyright (c) 2011 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 "base/file_util.h" 6 #include "base/memory/ref_counted.h" 7 #include "base/memory/scoped_temp_dir.h" 8 #include "base/message_loop.h" 9 #include "base/stl_util-inl.h" 10 #include "base/time.h" 11 #include "chrome/browser/net/sqlite_persistent_cookie_store.h" 12 #include "chrome/common/chrome_constants.h" 13 #include "chrome/test/thread_test_helper.h" 14 #include "content/browser/browser_thread.h" 15 #include "googleurl/src/gurl.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 class SQLitePersistentCookieStoreTest : public testing::Test { 19 public: 20 SQLitePersistentCookieStoreTest() 21 : ui_thread_(BrowserThread::UI), 22 db_thread_(BrowserThread::DB) { 23 } 24 25 protected: 26 virtual void SetUp() { 27 ui_thread_.Start(); 28 db_thread_.Start(); 29 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 30 store_ = new SQLitePersistentCookieStore( 31 temp_dir_.path().Append(chrome::kCookieFilename)); 32 std::vector<net::CookieMonster::CanonicalCookie*> cookies; 33 ASSERT_TRUE(store_->Load(&cookies)); 34 ASSERT_TRUE(0 == cookies.size()); 35 // Make sure the store gets written at least once. 36 store_->AddCookie( 37 net::CookieMonster::CanonicalCookie(GURL(), "A", "B", "http://foo.bar", 38 "/", base::Time::Now(), 39 base::Time::Now(), 40 base::Time::Now(), 41 false, false, true)); 42 } 43 44 BrowserThread ui_thread_; 45 BrowserThread db_thread_; 46 ScopedTempDir temp_dir_; 47 scoped_refptr<SQLitePersistentCookieStore> store_; 48 }; 49 50 TEST_F(SQLitePersistentCookieStoreTest, KeepOnDestruction) { 51 store_->SetClearLocalStateOnExit(false); 52 store_ = NULL; 53 // Make sure we wait until the destructor has run. 54 scoped_refptr<ThreadTestHelper> helper( 55 new ThreadTestHelper(BrowserThread::DB)); 56 ASSERT_TRUE(helper->Run()); 57 58 ASSERT_TRUE(file_util::PathExists( 59 temp_dir_.path().Append(chrome::kCookieFilename))); 60 ASSERT_TRUE(file_util::Delete( 61 temp_dir_.path().Append(chrome::kCookieFilename), false)); 62 } 63 64 TEST_F(SQLitePersistentCookieStoreTest, RemoveOnDestruction) { 65 store_->SetClearLocalStateOnExit(true); 66 // Replace the store effectively destroying the current one and forcing it 67 // to write it's data to disk. Then we can see if after loading it again it 68 // is still there. 69 store_ = NULL; 70 // Make sure we wait until the destructor has run. 71 scoped_refptr<ThreadTestHelper> helper( 72 new ThreadTestHelper(BrowserThread::DB)); 73 ASSERT_TRUE(helper->Run()); 74 75 ASSERT_FALSE(file_util::PathExists( 76 temp_dir_.path().Append(chrome::kCookieFilename))); 77 } 78 79 // Test if data is stored as expected in the SQLite database. 80 TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) { 81 std::vector<net::CookieMonster::CanonicalCookie*> cookies; 82 // Replace the store effectively destroying the current one and forcing it 83 // to write it's data to disk. Then we can see if after loading it again it 84 // is still there. 85 store_ = NULL; 86 scoped_refptr<ThreadTestHelper> helper( 87 new ThreadTestHelper(BrowserThread::DB)); 88 // Make sure we wait until the destructor has run. 89 ASSERT_TRUE(helper->Run()); 90 store_ = new SQLitePersistentCookieStore( 91 temp_dir_.path().Append(chrome::kCookieFilename)); 92 93 // Reload and test for persistence 94 ASSERT_TRUE(store_->Load(&cookies)); 95 ASSERT_EQ(1U, cookies.size()); 96 ASSERT_STREQ("http://foo.bar", cookies[0]->Domain().c_str()); 97 ASSERT_STREQ("A", cookies[0]->Name().c_str()); 98 ASSERT_STREQ("B", cookies[0]->Value().c_str()); 99 100 // Now delete the cookie and check persistence again. 101 store_->DeleteCookie(*cookies[0]); 102 store_ = NULL; 103 // Make sure we wait until the destructor has run. 104 ASSERT_TRUE(helper->Run()); 105 STLDeleteContainerPointers(cookies.begin(), cookies.end()); 106 cookies.clear(); 107 store_ = new SQLitePersistentCookieStore( 108 temp_dir_.path().Append(chrome::kCookieFilename)); 109 110 // Reload and check if the cookie has been removed. 111 ASSERT_TRUE(store_->Load(&cookies)); 112 ASSERT_EQ(0U, cookies.size()); 113 } 114 115 // Test that we can force the database to be written by calling Flush(). 116 TEST_F(SQLitePersistentCookieStoreTest, TestFlush) { 117 // File timestamps don't work well on all platforms, so we'll determine 118 // whether the DB file has been modified by checking its size. 119 FilePath path = temp_dir_.path().Append(chrome::kCookieFilename); 120 base::PlatformFileInfo info; 121 ASSERT_TRUE(file_util::GetFileInfo(path, &info)); 122 int64 base_size = info.size; 123 124 // Write some large cookies, so the DB will have to expand by several KB. 125 for (char c = 'a'; c < 'z'; ++c) { 126 // Each cookie needs a unique timestamp for creation_utc (see DB schema). 127 base::Time t = base::Time::Now() + base::TimeDelta::FromMicroseconds(c); 128 std::string name(1, c); 129 std::string value(1000, c); 130 store_->AddCookie( 131 net::CookieMonster::CanonicalCookie(GURL(), name, value, 132 "http://foo.bar", "/", t, t, t, 133 false, false, true)); 134 } 135 136 // Call Flush() and wait until the DB thread is idle. 137 store_->Flush(NULL); 138 scoped_refptr<ThreadTestHelper> helper( 139 new ThreadTestHelper(BrowserThread::DB)); 140 ASSERT_TRUE(helper->Run()); 141 142 // We forced a write, so now the file will be bigger. 143 ASSERT_TRUE(file_util::GetFileInfo(path, &info)); 144 ASSERT_GT(info.size, base_size); 145 } 146 147 // Counts the number of times Callback() has been run. 148 class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> { 149 public: 150 CallbackCounter() : callback_count_(0) {} 151 152 void Callback() { 153 ++callback_count_; 154 } 155 156 int callback_count() { 157 return callback_count_; 158 } 159 160 private: 161 friend class base::RefCountedThreadSafe<CallbackCounter>; 162 volatile int callback_count_; 163 }; 164 165 // Test that we can get a completion callback after a Flush(). 166 TEST_F(SQLitePersistentCookieStoreTest, TestFlushCompletionCallback) { 167 scoped_refptr<CallbackCounter> counter(new CallbackCounter()); 168 169 // Callback shouldn't be invoked until we call Flush(). 170 ASSERT_EQ(0, counter->callback_count()); 171 172 store_->Flush(NewRunnableMethod(counter.get(), &CallbackCounter::Callback)); 173 174 scoped_refptr<ThreadTestHelper> helper( 175 new ThreadTestHelper(BrowserThread::DB)); 176 ASSERT_TRUE(helper->Run()); 177 178 ASSERT_EQ(1, counter->callback_count()); 179 } 180