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 <map> 6 7#include "base/bind.h" 8#include "base/files/file_path.h" 9#include "base/message_loop/message_loop.h" 10#include "base/message_loop/message_loop_proxy.h" 11#include "base/strings/utf_string_conversions.h" 12#include "net/base/completion_callback.h" 13#include "net/base/net_errors.h" 14#include "testing/gtest/include/gtest/gtest.h" 15#include "webkit/browser/database/database_quota_client.h" 16#include "webkit/browser/database/database_tracker.h" 17#include "webkit/browser/database/database_util.h" 18#include "webkit/common/database/database_identifier.h" 19 20namespace webkit_database { 21 22// Declared to shorten the line lengths. 23static const quota::StorageType kTemp = quota::kStorageTypeTemporary; 24static const quota::StorageType kPerm = quota::kStorageTypePersistent; 25 26// Mock tracker class the mocks up those methods of the tracker 27// that are used by the QuotaClient. 28class MockDatabaseTracker : public DatabaseTracker { 29 public: 30 MockDatabaseTracker() 31 : DatabaseTracker(base::FilePath(), false, NULL, NULL, NULL), 32 delete_called_count_(0), 33 async_delete_(false) {} 34 35 virtual bool GetOriginInfo( 36 const std::string& origin_identifier, 37 OriginInfo* info) OVERRIDE { 38 std::map<GURL, MockOriginInfo>::const_iterator found = 39 mock_origin_infos_.find( 40 webkit_database::GetOriginFromIdentifier(origin_identifier)); 41 if (found == mock_origin_infos_.end()) 42 return false; 43 *info = OriginInfo(found->second); 44 return true; 45 } 46 47 virtual bool GetAllOriginIdentifiers( 48 std::vector<std::string>* origins_identifiers) OVERRIDE { 49 std::map<GURL, MockOriginInfo>::const_iterator iter; 50 for (iter = mock_origin_infos_.begin(); 51 iter != mock_origin_infos_.end(); 52 ++iter) { 53 origins_identifiers->push_back(iter->second.GetOriginIdentifier()); 54 } 55 return true; 56 } 57 58 virtual bool GetAllOriginsInfo( 59 std::vector<OriginInfo>* origins_info) OVERRIDE { 60 std::map<GURL, MockOriginInfo>::const_iterator iter; 61 for (iter = mock_origin_infos_.begin(); 62 iter != mock_origin_infos_.end(); 63 ++iter) { 64 origins_info->push_back(OriginInfo(iter->second)); 65 } 66 return true; 67 } 68 69 virtual int DeleteDataForOrigin( 70 const std::string& origin_identifier, 71 const net::CompletionCallback& callback) OVERRIDE { 72 ++delete_called_count_; 73 if (async_delete()) { 74 base::MessageLoopProxy::current()->PostTask( 75 FROM_HERE, 76 base::Bind(&MockDatabaseTracker::AsyncDeleteDataForOrigin, this, 77 callback)); 78 return net::ERR_IO_PENDING; 79 } 80 return net::OK; 81 } 82 83 void AsyncDeleteDataForOrigin(const net::CompletionCallback& callback) { 84 callback.Run(net::OK); 85 } 86 87 void AddMockDatabase(const GURL& origin, const char* name, int size) { 88 MockOriginInfo& info = mock_origin_infos_[origin]; 89 info.set_origin(webkit_database::GetIdentifierFromOrigin(origin)); 90 info.AddMockDatabase(ASCIIToUTF16(name), size); 91 } 92 93 int delete_called_count() { return delete_called_count_; } 94 bool async_delete() { return async_delete_; } 95 void set_async_delete(bool async) { async_delete_ = async; } 96 97 protected: 98 virtual ~MockDatabaseTracker() {} 99 100 private: 101 class MockOriginInfo : public OriginInfo { 102 public: 103 void set_origin(const std::string& origin_identifier) { 104 origin_identifier_ = origin_identifier; 105 } 106 107 void AddMockDatabase(const base::string16& name, int size) { 108 EXPECT_TRUE(database_info_.find(name) == database_info_.end()); 109 database_info_[name].first = size; 110 total_size_ += size; 111 } 112 }; 113 114 int delete_called_count_; 115 bool async_delete_; 116 std::map<GURL, MockOriginInfo> mock_origin_infos_; 117}; 118 119 120// Base class for our test fixtures. 121class DatabaseQuotaClientTest : public testing::Test { 122 public: 123 const GURL kOriginA; 124 const GURL kOriginB; 125 const GURL kOriginOther; 126 127 DatabaseQuotaClientTest() 128 : kOriginA("http://host"), 129 kOriginB("http://host:8000"), 130 kOriginOther("http://other"), 131 usage_(0), 132 mock_tracker_(new MockDatabaseTracker), 133 weak_factory_(this) { 134 } 135 136 int64 GetOriginUsage( 137 quota::QuotaClient* client, 138 const GURL& origin, 139 quota::StorageType type) { 140 usage_ = 0; 141 client->GetOriginUsage( 142 origin, type, 143 base::Bind(&DatabaseQuotaClientTest::OnGetOriginUsageComplete, 144 weak_factory_.GetWeakPtr())); 145 base::MessageLoop::current()->RunUntilIdle(); 146 return usage_; 147 } 148 149 const std::set<GURL>& GetOriginsForType( 150 quota::QuotaClient* client, 151 quota::StorageType type) { 152 origins_.clear(); 153 client->GetOriginsForType( 154 type, 155 base::Bind(&DatabaseQuotaClientTest::OnGetOriginsComplete, 156 weak_factory_.GetWeakPtr())); 157 base::MessageLoop::current()->RunUntilIdle(); 158 return origins_; 159 } 160 161 const std::set<GURL>& GetOriginsForHost( 162 quota::QuotaClient* client, 163 quota::StorageType type, 164 const std::string& host) { 165 origins_.clear(); 166 client->GetOriginsForHost( 167 type, host, 168 base::Bind(&DatabaseQuotaClientTest::OnGetOriginsComplete, 169 weak_factory_.GetWeakPtr())); 170 base::MessageLoop::current()->RunUntilIdle(); 171 return origins_; 172 } 173 174 bool DeleteOriginData( 175 quota::QuotaClient* client, 176 quota::StorageType type, 177 const GURL& origin) { 178 delete_status_ = quota::kQuotaStatusUnknown; 179 client->DeleteOriginData( 180 origin, type, 181 base::Bind(&DatabaseQuotaClientTest::OnDeleteOriginDataComplete, 182 weak_factory_.GetWeakPtr())); 183 base::MessageLoop::current()->RunUntilIdle(); 184 return delete_status_ == quota::kQuotaStatusOk; 185 } 186 187 MockDatabaseTracker* mock_tracker() { return mock_tracker_.get(); } 188 189 190 private: 191 void OnGetOriginUsageComplete(int64 usage) { 192 usage_ = usage; 193 } 194 195 void OnGetOriginsComplete(const std::set<GURL>& origins) { 196 origins_ = origins; 197 } 198 199 void OnDeleteOriginDataComplete(quota::QuotaStatusCode status) { 200 delete_status_ = status; 201 } 202 203 base::MessageLoop message_loop_; 204 int64 usage_; 205 std::set<GURL> origins_; 206 quota::QuotaStatusCode delete_status_; 207 scoped_refptr<MockDatabaseTracker> mock_tracker_; 208 base::WeakPtrFactory<DatabaseQuotaClientTest> weak_factory_; 209}; 210 211 212TEST_F(DatabaseQuotaClientTest, GetOriginUsage) { 213 DatabaseQuotaClient client(base::MessageLoopProxy::current().get(), 214 mock_tracker()); 215 216 EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kTemp)); 217 EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kPerm)); 218 219 mock_tracker()->AddMockDatabase(kOriginA, "fooDB", 1000); 220 EXPECT_EQ(1000, GetOriginUsage(&client, kOriginA, kTemp)); 221 EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kPerm)); 222 223 EXPECT_EQ(0, GetOriginUsage(&client, kOriginB, kPerm)); 224 EXPECT_EQ(0, GetOriginUsage(&client, kOriginB, kTemp)); 225} 226 227TEST_F(DatabaseQuotaClientTest, GetOriginsForHost) { 228 DatabaseQuotaClient client(base::MessageLoopProxy::current().get(), 229 mock_tracker()); 230 231 EXPECT_EQ(kOriginA.host(), kOriginB.host()); 232 EXPECT_NE(kOriginA.host(), kOriginOther.host()); 233 234 std::set<GURL> origins = GetOriginsForHost(&client, kTemp, kOriginA.host()); 235 EXPECT_TRUE(origins.empty()); 236 237 mock_tracker()->AddMockDatabase(kOriginA, "fooDB", 1000); 238 origins = GetOriginsForHost(&client, kTemp, kOriginA.host()); 239 EXPECT_EQ(origins.size(), 1ul); 240 EXPECT_TRUE(origins.find(kOriginA) != origins.end()); 241 242 mock_tracker()->AddMockDatabase(kOriginB, "barDB", 1000); 243 origins = GetOriginsForHost(&client, kTemp, kOriginA.host()); 244 EXPECT_EQ(origins.size(), 2ul); 245 EXPECT_TRUE(origins.find(kOriginA) != origins.end()); 246 EXPECT_TRUE(origins.find(kOriginB) != origins.end()); 247 248 EXPECT_TRUE(GetOriginsForHost(&client, kPerm, kOriginA.host()).empty()); 249 EXPECT_TRUE(GetOriginsForHost(&client, kTemp, kOriginOther.host()).empty()); 250} 251 252TEST_F(DatabaseQuotaClientTest, GetOriginsForType) { 253 DatabaseQuotaClient client(base::MessageLoopProxy::current().get(), 254 mock_tracker()); 255 256 EXPECT_TRUE(GetOriginsForType(&client, kTemp).empty()); 257 EXPECT_TRUE(GetOriginsForType(&client, kPerm).empty()); 258 259 mock_tracker()->AddMockDatabase(kOriginA, "fooDB", 1000); 260 std::set<GURL> origins = GetOriginsForType(&client, kTemp); 261 EXPECT_EQ(origins.size(), 1ul); 262 EXPECT_TRUE(origins.find(kOriginA) != origins.end()); 263 264 EXPECT_TRUE(GetOriginsForType(&client, kPerm).empty()); 265} 266 267TEST_F(DatabaseQuotaClientTest, DeleteOriginData) { 268 DatabaseQuotaClient client(base::MessageLoopProxy::current().get(), 269 mock_tracker()); 270 271 // Perm deletions are short circuited in the Client and 272 // should not reach the DatabaseTracker. 273 EXPECT_TRUE(DeleteOriginData(&client, kPerm, kOriginA)); 274 EXPECT_EQ(0, mock_tracker()->delete_called_count()); 275 276 mock_tracker()->set_async_delete(false); 277 EXPECT_TRUE(DeleteOriginData(&client, kTemp, kOriginA)); 278 EXPECT_EQ(1, mock_tracker()->delete_called_count()); 279 280 mock_tracker()->set_async_delete(true); 281 EXPECT_TRUE(DeleteOriginData(&client, kTemp, kOriginA)); 282 EXPECT_EQ(2, mock_tracker()->delete_called_count()); 283} 284 285} // namespace webkit_database 286