// Copyright 2013 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.
#include "base/bind.h"
#include "base/run_loop.h"
#include "net/base/net_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/quota/mock_special_storage_policy.h"
#include "webkit/browser/quota/usage_tracker.h"
namespace quota {
namespace {
void DidGetGlobalUsage(bool* done,
int64* usage_out,
int64* unlimited_usage_out,
int64 usage,
int64 unlimited_usage) {
EXPECT_FALSE(*done);
*done = true;
*usage_out = usage;
*unlimited_usage_out = unlimited_usage;
}
void DidGetUsage(bool* done,
int64* usage_out,
int64 usage) {
EXPECT_FALSE(*done);
*done = true;
*usage_out = usage;
}
} // namespace
class MockQuotaClient : public QuotaClient {
public:
MockQuotaClient() {}
virtual ~MockQuotaClient() {}
virtual ID id() const OVERRIDE {
return kFileSystem;
}
virtual void OnQuotaManagerDestroyed() OVERRIDE {}
virtual void GetOriginUsage(const GURL& origin,
StorageType type,
const GetUsageCallback& callback) OVERRIDE {
EXPECT_EQ(kStorageTypeTemporary, type);
int64 usage = GetUsage(origin);
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(callback, usage));
}
virtual void GetOriginsForType(StorageType type,
const GetOriginsCallback& callback) OVERRIDE {
EXPECT_EQ(kStorageTypeTemporary, type);
std::set<GURL> origins;
for (UsageMap::const_iterator itr = usage_map_.begin();
itr != usage_map_.end(); ++itr) {
origins.insert(itr->first);
}
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(callback, origins));
}
virtual void GetOriginsForHost(StorageType type,
const std::string& host,
const GetOriginsCallback& callback) OVERRIDE {
EXPECT_EQ(kStorageTypeTemporary, type);
std::set<GURL> origins;
for (UsageMap::const_iterator itr = usage_map_.begin();
itr != usage_map_.end(); ++itr) {
if (net::GetHostOrSpecFromURL(itr->first) == host)
origins.insert(itr->first);
}
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(callback, origins));
}
virtual void DeleteOriginData(const GURL& origin,
StorageType type,
const DeletionCallback& callback) OVERRIDE {
EXPECT_EQ(kStorageTypeTemporary, type);
usage_map_.erase(origin);
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, kQuotaStatusOk));
}
virtual bool DoesSupport(quota::StorageType type) const OVERRIDE {
return type == quota::kStorageTypeTemporary;
}
int64 GetUsage(const GURL& origin) {
UsageMap::const_iterator found = usage_map_.find(origin);
if (found == usage_map_.end())
return 0;
return found->second;
}
void SetUsage(const GURL& origin, int64 usage) {
usage_map_[origin] = usage;
}
int64 UpdateUsage(const GURL& origin, int64 delta) {
return usage_map_[origin] += delta;
}
private:
typedef std::map<GURL, int64> UsageMap;
UsageMap usage_map_;
DISALLOW_COPY_AND_ASSIGN(MockQuotaClient);
};
class UsageTrackerTest : public testing::Test {
public:
UsageTrackerTest()
: storage_policy_(new MockSpecialStoragePolicy()),
usage_tracker_(GetUsageTrackerList(), kStorageTypeTemporary,
storage_policy_.get()) {
}
virtual ~UsageTrackerTest() {}
UsageTracker* usage_tracker() {
return &usage_tracker_;
}
void UpdateUsage(const GURL& origin, int64 delta) {
quota_client_.UpdateUsage(origin, delta);
usage_tracker_.UpdateUsageCache(quota_client_.id(), origin, delta);
base::RunLoop().RunUntilIdle();
}
void UpdateUsageWithoutNotification(const GURL& origin, int64 delta) {
quota_client_.UpdateUsage(origin, delta);
}
void GetGlobalLimitedUsage(int64* limited_usage) {
bool done = false;
usage_tracker_.GetGlobalLimitedUsage(base::Bind(
&DidGetUsage, &done, limited_usage));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(done);
}
void GetGlobalUsage(int64* usage, int64* unlimited_usage) {
bool done = false;
usage_tracker_.GetGlobalUsage(base::Bind(
&DidGetGlobalUsage,
&done, usage, unlimited_usage));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(done);
}
void GetHostUsage(const std::string& host, int64* usage) {
bool done = false;
usage_tracker_.GetHostUsage(host, base::Bind(&DidGetUsage, &done, usage));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(done);
}
void GrantUnlimitedStoragePolicy(const GURL& origin) {
if (!storage_policy_->IsStorageUnlimited(origin)) {
storage_policy_->AddUnlimited(origin);
storage_policy_->NotifyGranted(
origin, SpecialStoragePolicy::STORAGE_UNLIMITED);
}
}
void RevokeUnlimitedStoragePolicy(const GURL& origin) {
if (storage_policy_->IsStorageUnlimited(origin)) {
storage_policy_->RemoveUnlimited(origin);
storage_policy_->NotifyRevoked(
origin, SpecialStoragePolicy::STORAGE_UNLIMITED);
}
}
void SetUsageCacheEnabled(const GURL& origin, bool enabled) {
usage_tracker_.SetUsageCacheEnabled(
quota_client_.id(), origin, enabled);
}
private:
QuotaClientList GetUsageTrackerList() {
QuotaClientList client_list;
client_list.push_back("a_client_);
return client_list;
}
base::MessageLoop message_loop_;
scoped_refptr<MockSpecialStoragePolicy> storage_policy_;
MockQuotaClient quota_client_;
UsageTracker usage_tracker_;
DISALLOW_COPY_AND_ASSIGN(UsageTrackerTest);
};
TEST_F(UsageTrackerTest, GrantAndRevokeUnlimitedStorage) {
int64 usage = 0;
int64 unlimited_usage = 0;
int64 host_usage = 0;
GetGlobalUsage(&usage, &unlimited_usage);
EXPECT_EQ(0, usage);
EXPECT_EQ(0, unlimited_usage);
const GURL origin("http://example.com");
const std::string host(net::GetHostOrSpecFromURL(origin));
UpdateUsage(origin, 100);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(100, usage);
EXPECT_EQ(0, unlimited_usage);
EXPECT_EQ(100, host_usage);
GrantUnlimitedStoragePolicy(origin);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(100, usage);
EXPECT_EQ(100, unlimited_usage);
EXPECT_EQ(100, host_usage);
RevokeUnlimitedStoragePolicy(origin);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(100, usage);
EXPECT_EQ(0, unlimited_usage);
EXPECT_EQ(100, host_usage);
}
TEST_F(UsageTrackerTest, CacheDisabledClientTest) {
int64 usage = 0;
int64 unlimited_usage = 0;
int64 host_usage = 0;
const GURL origin("http://example.com");
const std::string host(net::GetHostOrSpecFromURL(origin));
UpdateUsage(origin, 100);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(100, usage);
EXPECT_EQ(0, unlimited_usage);
EXPECT_EQ(100, host_usage);
UpdateUsageWithoutNotification(origin, 100);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(100, usage);
EXPECT_EQ(0, unlimited_usage);
EXPECT_EQ(100, host_usage);
GrantUnlimitedStoragePolicy(origin);
UpdateUsageWithoutNotification(origin, 100);
SetUsageCacheEnabled(origin, false);
UpdateUsageWithoutNotification(origin, 100);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(400, usage);
EXPECT_EQ(400, unlimited_usage);
EXPECT_EQ(400, host_usage);
RevokeUnlimitedStoragePolicy(origin);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(400, usage);
EXPECT_EQ(0, unlimited_usage);
EXPECT_EQ(400, host_usage);
SetUsageCacheEnabled(origin, true);
UpdateUsage(origin, 100);
GetGlobalUsage(&usage, &unlimited_usage);
GetHostUsage(host, &host_usage);
EXPECT_EQ(500, usage);
EXPECT_EQ(0, unlimited_usage);
EXPECT_EQ(500, host_usage);
}
TEST_F(UsageTrackerTest, LimitedGlobalUsageTest) {
const GURL kNormal("http://normal");
const GURL kUnlimited("http://unlimited");
const GURL kNonCached("http://non_cached");
const GURL kNonCachedUnlimited("http://non_cached-unlimited");
GrantUnlimitedStoragePolicy(kUnlimited);
GrantUnlimitedStoragePolicy(kNonCachedUnlimited);
SetUsageCacheEnabled(kNonCached, false);
SetUsageCacheEnabled(kNonCachedUnlimited, false);
UpdateUsageWithoutNotification(kNormal, 1);
UpdateUsageWithoutNotification(kUnlimited, 2);
UpdateUsageWithoutNotification(kNonCached, 4);
UpdateUsageWithoutNotification(kNonCachedUnlimited, 8);
int64 limited_usage = 0;
int64 total_usage = 0;
int64 unlimited_usage = 0;
GetGlobalLimitedUsage(&limited_usage);
GetGlobalUsage(&total_usage, &unlimited_usage);
EXPECT_EQ(1 + 4, limited_usage);
EXPECT_EQ(1 + 2 + 4 + 8, total_usage);
EXPECT_EQ(2 + 8, unlimited_usage);
UpdateUsageWithoutNotification(kNonCached, 16 - 4);
UpdateUsageWithoutNotification(kNonCachedUnlimited, 32 - 8);
GetGlobalLimitedUsage(&limited_usage);
GetGlobalUsage(&total_usage, &unlimited_usage);
EXPECT_EQ(1 + 16, limited_usage);
EXPECT_EQ(1 + 2 + 16 + 32, total_usage);
EXPECT_EQ(2 + 32, unlimited_usage);
}
} // namespace quota