1 // Copyright 2014 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_proxy.h" 10 #include "base/run_loop.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 "storage/browser/database/database_quota_client.h" 15 #include "storage/browser/database/database_tracker.h" 16 #include "storage/browser/database/database_util.h" 17 #include "storage/common/database/database_identifier.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 using storage::DatabaseQuotaClient; 21 using storage::DatabaseTracker; 22 using storage::OriginInfo; 23 24 namespace content { 25 26 // Declared to shorten the line lengths. 27 static const storage::StorageType kTemp = storage::kStorageTypeTemporary; 28 static const storage::StorageType kPerm = storage::kStorageTypePersistent; 29 30 // Mock tracker class the mocks up those methods of the tracker 31 // that are used by the QuotaClient. 32 class MockDatabaseTracker : public DatabaseTracker { 33 public: 34 MockDatabaseTracker() 35 : DatabaseTracker(base::FilePath(), false, NULL, NULL, NULL), 36 delete_called_count_(0), 37 async_delete_(false) {} 38 39 virtual bool GetOriginInfo( 40 const std::string& origin_identifier, 41 OriginInfo* info) OVERRIDE { 42 std::map<GURL, MockOriginInfo>::const_iterator found = 43 mock_origin_infos_.find( 44 storage::GetOriginFromIdentifier(origin_identifier)); 45 if (found == mock_origin_infos_.end()) 46 return false; 47 *info = OriginInfo(found->second); 48 return true; 49 } 50 51 virtual bool GetAllOriginIdentifiers( 52 std::vector<std::string>* origins_identifiers) OVERRIDE { 53 std::map<GURL, MockOriginInfo>::const_iterator iter; 54 for (iter = mock_origin_infos_.begin(); 55 iter != mock_origin_infos_.end(); 56 ++iter) { 57 origins_identifiers->push_back(iter->second.GetOriginIdentifier()); 58 } 59 return true; 60 } 61 62 virtual bool GetAllOriginsInfo( 63 std::vector<OriginInfo>* origins_info) OVERRIDE { 64 std::map<GURL, MockOriginInfo>::const_iterator iter; 65 for (iter = mock_origin_infos_.begin(); 66 iter != mock_origin_infos_.end(); 67 ++iter) { 68 origins_info->push_back(OriginInfo(iter->second)); 69 } 70 return true; 71 } 72 73 virtual int DeleteDataForOrigin( 74 const std::string& origin_identifier, 75 const net::CompletionCallback& callback) OVERRIDE { 76 ++delete_called_count_; 77 if (async_delete()) { 78 base::MessageLoopProxy::current()->PostTask( 79 FROM_HERE, 80 base::Bind(&MockDatabaseTracker::AsyncDeleteDataForOrigin, this, 81 callback)); 82 return net::ERR_IO_PENDING; 83 } 84 return net::OK; 85 } 86 87 void AsyncDeleteDataForOrigin(const net::CompletionCallback& callback) { 88 callback.Run(net::OK); 89 } 90 91 void AddMockDatabase(const GURL& origin, const char* name, int size) { 92 MockOriginInfo& info = mock_origin_infos_[origin]; 93 info.set_origin(storage::GetIdentifierFromOrigin(origin)); 94 info.AddMockDatabase(base::ASCIIToUTF16(name), size); 95 } 96 97 int delete_called_count() { return delete_called_count_; } 98 bool async_delete() { return async_delete_; } 99 void set_async_delete(bool async) { async_delete_ = async; } 100 101 protected: 102 virtual ~MockDatabaseTracker() {} 103 104 private: 105 class MockOriginInfo : public OriginInfo { 106 public: 107 void set_origin(const std::string& origin_identifier) { 108 origin_identifier_ = origin_identifier; 109 } 110 111 void AddMockDatabase(const base::string16& name, int size) { 112 EXPECT_TRUE(database_info_.find(name) == database_info_.end()); 113 database_info_[name].first = size; 114 total_size_ += size; 115 } 116 }; 117 118 int delete_called_count_; 119 bool async_delete_; 120 std::map<GURL, MockOriginInfo> mock_origin_infos_; 121 }; 122 123 124 // Base class for our test fixtures. 125 class DatabaseQuotaClientTest : public testing::Test { 126 public: 127 const GURL kOriginA; 128 const GURL kOriginB; 129 const GURL kOriginOther; 130 131 DatabaseQuotaClientTest() 132 : kOriginA("http://host"), 133 kOriginB("http://host:8000"), 134 kOriginOther("http://other"), 135 usage_(0), 136 mock_tracker_(new MockDatabaseTracker), 137 weak_factory_(this) { 138 } 139 140 int64 GetOriginUsage(storage::QuotaClient* client, 141 const GURL& origin, 142 storage::StorageType type) { 143 usage_ = 0; 144 client->GetOriginUsage( 145 origin, type, 146 base::Bind(&DatabaseQuotaClientTest::OnGetOriginUsageComplete, 147 weak_factory_.GetWeakPtr())); 148 base::RunLoop().RunUntilIdle(); 149 return usage_; 150 } 151 152 const std::set<GURL>& GetOriginsForType(storage::QuotaClient* client, 153 storage::StorageType type) { 154 origins_.clear(); 155 client->GetOriginsForType( 156 type, 157 base::Bind(&DatabaseQuotaClientTest::OnGetOriginsComplete, 158 weak_factory_.GetWeakPtr())); 159 base::RunLoop().RunUntilIdle(); 160 return origins_; 161 } 162 163 const std::set<GURL>& GetOriginsForHost(storage::QuotaClient* client, 164 storage::StorageType type, 165 const std::string& host) { 166 origins_.clear(); 167 client->GetOriginsForHost( 168 type, host, 169 base::Bind(&DatabaseQuotaClientTest::OnGetOriginsComplete, 170 weak_factory_.GetWeakPtr())); 171 base::RunLoop().RunUntilIdle(); 172 return origins_; 173 } 174 175 bool DeleteOriginData(storage::QuotaClient* client, 176 storage::StorageType type, 177 const GURL& origin) { 178 delete_status_ = storage::kQuotaStatusUnknown; 179 client->DeleteOriginData( 180 origin, type, 181 base::Bind(&DatabaseQuotaClientTest::OnDeleteOriginDataComplete, 182 weak_factory_.GetWeakPtr())); 183 base::RunLoop().RunUntilIdle(); 184 return delete_status_ == storage::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(storage::QuotaStatusCode status) { 200 delete_status_ = status; 201 } 202 203 base::MessageLoop message_loop_; 204 int64 usage_; 205 std::set<GURL> origins_; 206 storage::QuotaStatusCode delete_status_; 207 scoped_refptr<MockDatabaseTracker> mock_tracker_; 208 base::WeakPtrFactory<DatabaseQuotaClientTest> weak_factory_; 209 }; 210 211 212 TEST_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 227 TEST_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 252 TEST_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 267 TEST_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 content 286