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 #include <set> 7 8 #include "base/bind.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "net/base/net_errors.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "webkit/browser/appcache/appcache_quota_client.h" 14 #include "webkit/browser/appcache/mock_appcache_service.h" 15 16 namespace appcache { 17 18 // Declared to shorten the line lengths. 19 static const quota::StorageType kTemp = quota::kStorageTypeTemporary; 20 static const quota::StorageType kPerm = quota::kStorageTypePersistent; 21 22 // Base class for our test fixtures. 23 class AppCacheQuotaClientTest : public testing::Test { 24 public: 25 const GURL kOriginA; 26 const GURL kOriginB; 27 const GURL kOriginOther; 28 29 AppCacheQuotaClientTest() 30 : kOriginA("http://host"), 31 kOriginB("http://host:8000"), 32 kOriginOther("http://other"), 33 usage_(0), 34 delete_status_(quota::kQuotaStatusUnknown), 35 num_get_origin_usage_completions_(0), 36 num_get_origins_completions_(0), 37 num_delete_origins_completions_(0), 38 weak_factory_(this) { 39 } 40 41 int64 GetOriginUsage( 42 quota::QuotaClient* client, 43 const GURL& origin, 44 quota::StorageType type) { 45 usage_ = -1; 46 AsyncGetOriginUsage(client, origin, type); 47 base::MessageLoop::current()->RunUntilIdle(); 48 return usage_; 49 } 50 51 const std::set<GURL>& GetOriginsForType( 52 quota::QuotaClient* client, 53 quota::StorageType type) { 54 origins_.clear(); 55 AsyncGetOriginsForType(client, type); 56 base::MessageLoop::current()->RunUntilIdle(); 57 return origins_; 58 } 59 60 const std::set<GURL>& GetOriginsForHost( 61 quota::QuotaClient* client, 62 quota::StorageType type, 63 const std::string& host) { 64 origins_.clear(); 65 AsyncGetOriginsForHost(client, type, host); 66 base::MessageLoop::current()->RunUntilIdle(); 67 return origins_; 68 } 69 70 quota::QuotaStatusCode DeleteOriginData( 71 quota::QuotaClient* client, 72 quota::StorageType type, 73 const GURL& origin) { 74 delete_status_ = quota::kQuotaStatusUnknown; 75 AsyncDeleteOriginData(client, type, origin); 76 base::MessageLoop::current()->RunUntilIdle(); 77 return delete_status_; 78 } 79 80 void AsyncGetOriginUsage( 81 quota::QuotaClient* client, 82 const GURL& origin, 83 quota::StorageType type) { 84 client->GetOriginUsage( 85 origin, type, 86 base::Bind(&AppCacheQuotaClientTest::OnGetOriginUsageComplete, 87 weak_factory_.GetWeakPtr())); 88 } 89 90 void AsyncGetOriginsForType( 91 quota::QuotaClient* client, 92 quota::StorageType type) { 93 client->GetOriginsForType( 94 type, 95 base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete, 96 weak_factory_.GetWeakPtr())); 97 } 98 99 void AsyncGetOriginsForHost( 100 quota::QuotaClient* client, 101 quota::StorageType type, 102 const std::string& host) { 103 client->GetOriginsForHost( 104 type, host, 105 base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete, 106 weak_factory_.GetWeakPtr())); 107 } 108 109 void AsyncDeleteOriginData( 110 quota::QuotaClient* client, 111 quota::StorageType type, 112 const GURL& origin) { 113 client->DeleteOriginData( 114 origin, type, 115 base::Bind(&AppCacheQuotaClientTest::OnDeleteOriginDataComplete, 116 weak_factory_.GetWeakPtr())); 117 } 118 119 void SetUsageMapEntry(const GURL& origin, int64 usage) { 120 mock_service_.storage()->usage_map_[origin] = usage; 121 } 122 123 AppCacheQuotaClient* CreateClient() { 124 return new AppCacheQuotaClient(&mock_service_); 125 } 126 127 void Call_NotifyAppCacheReady(AppCacheQuotaClient* client) { 128 client->NotifyAppCacheReady(); 129 } 130 131 void Call_NotifyAppCacheDestroyed(AppCacheQuotaClient* client) { 132 client->NotifyAppCacheDestroyed(); 133 } 134 135 void Call_OnQuotaManagerDestroyed(AppCacheQuotaClient* client) { 136 client->OnQuotaManagerDestroyed(); 137 } 138 139 protected: 140 void OnGetOriginUsageComplete(int64 usage) { 141 ++num_get_origin_usage_completions_; 142 usage_ = usage; 143 } 144 145 void OnGetOriginsComplete(const std::set<GURL>& origins) { 146 ++num_get_origins_completions_; 147 origins_ = origins; 148 } 149 150 void OnDeleteOriginDataComplete(quota::QuotaStatusCode status) { 151 ++num_delete_origins_completions_; 152 delete_status_ = status; 153 } 154 155 base::MessageLoop message_loop_; 156 int64 usage_; 157 std::set<GURL> origins_; 158 quota::QuotaStatusCode delete_status_; 159 int num_get_origin_usage_completions_; 160 int num_get_origins_completions_; 161 int num_delete_origins_completions_; 162 MockAppCacheService mock_service_; 163 base::WeakPtrFactory<AppCacheQuotaClientTest> weak_factory_; 164 }; 165 166 167 TEST_F(AppCacheQuotaClientTest, BasicCreateDestroy) { 168 AppCacheQuotaClient* client = CreateClient(); 169 Call_NotifyAppCacheReady(client); 170 Call_OnQuotaManagerDestroyed(client); 171 Call_NotifyAppCacheDestroyed(client); 172 } 173 174 TEST_F(AppCacheQuotaClientTest, EmptyService) { 175 AppCacheQuotaClient* client = CreateClient(); 176 Call_NotifyAppCacheReady(client); 177 178 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kTemp)); 179 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm)); 180 EXPECT_TRUE(GetOriginsForType(client, kTemp).empty()); 181 EXPECT_TRUE(GetOriginsForType(client, kPerm).empty()); 182 EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty()); 183 EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty()); 184 EXPECT_EQ(quota::kQuotaStatusOk, DeleteOriginData(client, kTemp, kOriginA)); 185 EXPECT_EQ(quota::kQuotaStatusOk, DeleteOriginData(client, kPerm, kOriginA)); 186 187 Call_NotifyAppCacheDestroyed(client); 188 Call_OnQuotaManagerDestroyed(client); 189 } 190 191 TEST_F(AppCacheQuotaClientTest, NoService) { 192 AppCacheQuotaClient* client = CreateClient(); 193 Call_NotifyAppCacheReady(client); 194 Call_NotifyAppCacheDestroyed(client); 195 196 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kTemp)); 197 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm)); 198 EXPECT_TRUE(GetOriginsForType(client, kTemp).empty()); 199 EXPECT_TRUE(GetOriginsForType(client, kPerm).empty()); 200 EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty()); 201 EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty()); 202 EXPECT_EQ(quota::kQuotaErrorAbort, 203 DeleteOriginData(client, kTemp, kOriginA)); 204 EXPECT_EQ(quota::kQuotaErrorAbort, 205 DeleteOriginData(client, kPerm, kOriginA)); 206 207 Call_OnQuotaManagerDestroyed(client); 208 } 209 210 TEST_F(AppCacheQuotaClientTest, GetOriginUsage) { 211 AppCacheQuotaClient* client = CreateClient(); 212 Call_NotifyAppCacheReady(client); 213 214 SetUsageMapEntry(kOriginA, 1000); 215 EXPECT_EQ(1000, GetOriginUsage(client, kOriginA, kTemp)); 216 EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm)); 217 218 Call_NotifyAppCacheDestroyed(client); 219 Call_OnQuotaManagerDestroyed(client); 220 } 221 222 TEST_F(AppCacheQuotaClientTest, GetOriginsForHost) { 223 AppCacheQuotaClient* client = CreateClient(); 224 Call_NotifyAppCacheReady(client); 225 226 EXPECT_EQ(kOriginA.host(), kOriginB.host()); 227 EXPECT_NE(kOriginA.host(), kOriginOther.host()); 228 229 std::set<GURL> origins = GetOriginsForHost(client, kTemp, kOriginA.host()); 230 EXPECT_TRUE(origins.empty()); 231 232 SetUsageMapEntry(kOriginA, 1000); 233 SetUsageMapEntry(kOriginB, 10); 234 SetUsageMapEntry(kOriginOther, 500); 235 236 origins = GetOriginsForHost(client, kTemp, kOriginA.host()); 237 EXPECT_EQ(2ul, origins.size()); 238 EXPECT_TRUE(origins.find(kOriginA) != origins.end()); 239 EXPECT_TRUE(origins.find(kOriginB) != origins.end()); 240 241 origins = GetOriginsForHost(client, kTemp, kOriginOther.host()); 242 EXPECT_EQ(1ul, origins.size()); 243 EXPECT_TRUE(origins.find(kOriginOther) != origins.end()); 244 245 origins = GetOriginsForHost(client, kPerm, kOriginA.host()); 246 EXPECT_TRUE(origins.empty()); 247 248 Call_NotifyAppCacheDestroyed(client); 249 Call_OnQuotaManagerDestroyed(client); 250 } 251 252 TEST_F(AppCacheQuotaClientTest, GetOriginsForType) { 253 AppCacheQuotaClient* client = CreateClient(); 254 Call_NotifyAppCacheReady(client); 255 256 EXPECT_TRUE(GetOriginsForType(client, kTemp).empty()); 257 EXPECT_TRUE(GetOriginsForType(client, kPerm).empty()); 258 259 SetUsageMapEntry(kOriginA, 1000); 260 SetUsageMapEntry(kOriginB, 10); 261 262 std::set<GURL> origins = GetOriginsForType(client, kTemp); 263 EXPECT_EQ(2ul, origins.size()); 264 EXPECT_TRUE(origins.find(kOriginA) != origins.end()); 265 EXPECT_TRUE(origins.find(kOriginB) != origins.end()); 266 267 EXPECT_TRUE(GetOriginsForType(client, kPerm).empty()); 268 269 Call_NotifyAppCacheDestroyed(client); 270 Call_OnQuotaManagerDestroyed(client); 271 } 272 273 TEST_F(AppCacheQuotaClientTest, DeleteOriginData) { 274 AppCacheQuotaClient* client = CreateClient(); 275 Call_NotifyAppCacheReady(client); 276 277 // Perm deletions are short circuited in the Client and 278 // should not reach the AppCacheService. 279 EXPECT_EQ(quota::kQuotaStatusOk, 280 DeleteOriginData(client, kPerm, kOriginA)); 281 EXPECT_EQ(0, mock_service_.delete_called_count()); 282 283 EXPECT_EQ(quota::kQuotaStatusOk, 284 DeleteOriginData(client, kTemp, kOriginA)); 285 EXPECT_EQ(1, mock_service_.delete_called_count()); 286 287 mock_service_.set_mock_delete_appcaches_for_origin_result( 288 net::ERR_ABORTED); 289 EXPECT_EQ(quota::kQuotaErrorAbort, 290 DeleteOriginData(client, kTemp, kOriginA)); 291 EXPECT_EQ(2, mock_service_.delete_called_count()); 292 293 Call_OnQuotaManagerDestroyed(client); 294 Call_NotifyAppCacheDestroyed(client); 295 } 296 297 TEST_F(AppCacheQuotaClientTest, PendingRequests) { 298 AppCacheQuotaClient* client = CreateClient(); 299 300 SetUsageMapEntry(kOriginA, 1000); 301 SetUsageMapEntry(kOriginB, 10); 302 SetUsageMapEntry(kOriginOther, 500); 303 304 // Queue up some reqeusts. 305 AsyncGetOriginUsage(client, kOriginA, kPerm); 306 AsyncGetOriginUsage(client, kOriginB, kTemp); 307 AsyncGetOriginsForType(client, kPerm); 308 AsyncGetOriginsForType(client, kTemp); 309 AsyncGetOriginsForHost(client, kTemp, kOriginA.host()); 310 AsyncGetOriginsForHost(client, kTemp, kOriginOther.host()); 311 AsyncDeleteOriginData(client, kTemp, kOriginA); 312 AsyncDeleteOriginData(client, kPerm, kOriginA); 313 AsyncDeleteOriginData(client, kTemp, kOriginB); 314 315 EXPECT_EQ(0, num_get_origin_usage_completions_); 316 EXPECT_EQ(0, num_get_origins_completions_); 317 EXPECT_EQ(0, num_delete_origins_completions_); 318 base::MessageLoop::current()->RunUntilIdle(); 319 EXPECT_EQ(0, num_get_origin_usage_completions_); 320 EXPECT_EQ(0, num_get_origins_completions_); 321 EXPECT_EQ(0, num_delete_origins_completions_); 322 323 // Pending requests should get serviced when the appcache is ready. 324 Call_NotifyAppCacheReady(client); 325 EXPECT_EQ(2, num_get_origin_usage_completions_); 326 EXPECT_EQ(4, num_get_origins_completions_); 327 EXPECT_EQ(0, num_delete_origins_completions_); 328 base::MessageLoop::current()->RunUntilIdle(); 329 EXPECT_EQ(3, num_delete_origins_completions_); // deletes are really async 330 331 // They should be serviced in order requested. 332 EXPECT_EQ(10, usage_); 333 EXPECT_EQ(1ul, origins_.size()); 334 EXPECT_TRUE(origins_.find(kOriginOther) != origins_.end()); 335 336 Call_NotifyAppCacheDestroyed(client); 337 Call_OnQuotaManagerDestroyed(client); 338 } 339 340 TEST_F(AppCacheQuotaClientTest, DestroyServiceWithPending) { 341 AppCacheQuotaClient* client = CreateClient(); 342 343 SetUsageMapEntry(kOriginA, 1000); 344 SetUsageMapEntry(kOriginB, 10); 345 SetUsageMapEntry(kOriginOther, 500); 346 347 // Queue up some reqeusts prior to being ready. 348 AsyncGetOriginUsage(client, kOriginA, kPerm); 349 AsyncGetOriginUsage(client, kOriginB, kTemp); 350 AsyncGetOriginsForType(client, kPerm); 351 AsyncGetOriginsForType(client, kTemp); 352 AsyncGetOriginsForHost(client, kTemp, kOriginA.host()); 353 AsyncGetOriginsForHost(client, kTemp, kOriginOther.host()); 354 AsyncDeleteOriginData(client, kTemp, kOriginA); 355 AsyncDeleteOriginData(client, kPerm, kOriginA); 356 AsyncDeleteOriginData(client, kTemp, kOriginB); 357 base::MessageLoop::current()->RunUntilIdle(); 358 EXPECT_EQ(0, num_get_origin_usage_completions_); 359 EXPECT_EQ(0, num_get_origins_completions_); 360 EXPECT_EQ(0, num_delete_origins_completions_); 361 362 // Kill the service. 363 Call_NotifyAppCacheDestroyed(client); 364 365 // All should have been aborted and called completion. 366 EXPECT_EQ(2, num_get_origin_usage_completions_); 367 EXPECT_EQ(4, num_get_origins_completions_); 368 EXPECT_EQ(3, num_delete_origins_completions_); 369 EXPECT_EQ(0, usage_); 370 EXPECT_TRUE(origins_.empty()); 371 EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_); 372 373 Call_OnQuotaManagerDestroyed(client); 374 } 375 376 TEST_F(AppCacheQuotaClientTest, DestroyQuotaManagerWithPending) { 377 AppCacheQuotaClient* client = CreateClient(); 378 379 SetUsageMapEntry(kOriginA, 1000); 380 SetUsageMapEntry(kOriginB, 10); 381 SetUsageMapEntry(kOriginOther, 500); 382 383 // Queue up some reqeusts prior to being ready. 384 AsyncGetOriginUsage(client, kOriginA, kPerm); 385 AsyncGetOriginUsage(client, kOriginB, kTemp); 386 AsyncGetOriginsForType(client, kPerm); 387 AsyncGetOriginsForType(client, kTemp); 388 AsyncGetOriginsForHost(client, kTemp, kOriginA.host()); 389 AsyncGetOriginsForHost(client, kTemp, kOriginOther.host()); 390 AsyncDeleteOriginData(client, kTemp, kOriginA); 391 AsyncDeleteOriginData(client, kPerm, kOriginA); 392 AsyncDeleteOriginData(client, kTemp, kOriginB); 393 base::MessageLoop::current()->RunUntilIdle(); 394 EXPECT_EQ(0, num_get_origin_usage_completions_); 395 EXPECT_EQ(0, num_get_origins_completions_); 396 EXPECT_EQ(0, num_delete_origins_completions_); 397 398 // Kill the quota manager. 399 Call_OnQuotaManagerDestroyed(client); 400 Call_NotifyAppCacheReady(client); 401 402 // Callbacks should be deleted and not called. 403 base::MessageLoop::current()->RunUntilIdle(); 404 EXPECT_EQ(0, num_get_origin_usage_completions_); 405 EXPECT_EQ(0, num_get_origins_completions_); 406 EXPECT_EQ(0, num_delete_origins_completions_); 407 408 Call_NotifyAppCacheDestroyed(client); 409 } 410 411 TEST_F(AppCacheQuotaClientTest, DestroyWithDeleteInProgress) { 412 AppCacheQuotaClient* client = CreateClient(); 413 Call_NotifyAppCacheReady(client); 414 415 // Start an async delete. 416 AsyncDeleteOriginData(client, kTemp, kOriginB); 417 EXPECT_EQ(0, num_delete_origins_completions_); 418 419 // Kill the service. 420 Call_NotifyAppCacheDestroyed(client); 421 422 // Should have been aborted. 423 EXPECT_EQ(1, num_delete_origins_completions_); 424 EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_); 425 426 // A real completion callback from the service should 427 // be dropped if it comes in after NotifyAppCacheDestroyed. 428 base::MessageLoop::current()->RunUntilIdle(); 429 EXPECT_EQ(1, num_delete_origins_completions_); 430 EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_); 431 432 Call_OnQuotaManagerDestroyed(client); 433 } 434 435 } // namespace appcache 436