root/webkit/browser/appcache/appcache_quota_client_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. weak_factory_
  2. GetOriginUsage
  3. GetOriginsForType
  4. GetOriginsForHost
  5. DeleteOriginData
  6. AsyncGetOriginUsage
  7. AsyncGetOriginsForType
  8. AsyncGetOriginsForHost
  9. AsyncDeleteOriginData
  10. SetUsageMapEntry
  11. CreateClient
  12. Call_NotifyAppCacheReady
  13. Call_NotifyAppCacheDestroyed
  14. Call_OnQuotaManagerDestroyed
  15. OnGetOriginUsageComplete
  16. OnGetOriginsComplete
  17. OnDeleteOriginDataComplete
  18. TEST_F
  19. TEST_F
  20. TEST_F
  21. TEST_F
  22. TEST_F
  23. TEST_F
  24. TEST_F
  25. TEST_F
  26. TEST_F
  27. TEST_F
  28. TEST_F

// Copyright (c) 2012 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 <map>
#include <set>

#include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/browser/appcache/appcache_quota_client.h"
#include "webkit/browser/appcache/mock_appcache_service.h"

namespace appcache {

// Declared to shorten the line lengths.
static const quota::StorageType kTemp = quota::kStorageTypeTemporary;
static const quota::StorageType kPerm = quota::kStorageTypePersistent;

// Base class for our test fixtures.
class AppCacheQuotaClientTest : public testing::Test {
 public:
  const GURL kOriginA;
  const GURL kOriginB;
  const GURL kOriginOther;

  AppCacheQuotaClientTest()
      : kOriginA("http://host"),
        kOriginB("http://host:8000"),
        kOriginOther("http://other"),
        usage_(0),
        delete_status_(quota::kQuotaStatusUnknown),
        num_get_origin_usage_completions_(0),
        num_get_origins_completions_(0),
        num_delete_origins_completions_(0),
        weak_factory_(this) {
  }

  int64 GetOriginUsage(
      quota::QuotaClient* client,
      const GURL& origin,
      quota::StorageType type) {
    usage_ = -1;
    AsyncGetOriginUsage(client, origin, type);
    base::RunLoop().RunUntilIdle();
    return usage_;
  }

  const std::set<GURL>& GetOriginsForType(
      quota::QuotaClient* client,
      quota::StorageType type) {
    origins_.clear();
    AsyncGetOriginsForType(client, type);
    base::RunLoop().RunUntilIdle();
    return origins_;
  }

  const std::set<GURL>& GetOriginsForHost(
      quota::QuotaClient* client,
      quota::StorageType type,
      const std::string& host) {
    origins_.clear();
    AsyncGetOriginsForHost(client, type, host);
    base::RunLoop().RunUntilIdle();
    return origins_;
  }

  quota::QuotaStatusCode DeleteOriginData(
      quota::QuotaClient* client,
      quota::StorageType type,
      const GURL& origin) {
    delete_status_ = quota::kQuotaStatusUnknown;
    AsyncDeleteOriginData(client, type, origin);
    base::RunLoop().RunUntilIdle();
    return delete_status_;
  }

  void AsyncGetOriginUsage(
      quota::QuotaClient* client,
      const GURL& origin,
      quota::StorageType type) {
    client->GetOriginUsage(
        origin, type,
        base::Bind(&AppCacheQuotaClientTest::OnGetOriginUsageComplete,
                   weak_factory_.GetWeakPtr()));
  }

  void AsyncGetOriginsForType(
      quota::QuotaClient* client,
      quota::StorageType type) {
    client->GetOriginsForType(
        type,
        base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete,
                   weak_factory_.GetWeakPtr()));
  }

  void AsyncGetOriginsForHost(
      quota::QuotaClient* client,
      quota::StorageType type,
      const std::string& host) {
    client->GetOriginsForHost(
        type, host,
        base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete,
                   weak_factory_.GetWeakPtr()));
  }

  void AsyncDeleteOriginData(
      quota::QuotaClient* client,
      quota::StorageType type,
      const GURL& origin) {
    client->DeleteOriginData(
        origin, type,
        base::Bind(&AppCacheQuotaClientTest::OnDeleteOriginDataComplete,
                   weak_factory_.GetWeakPtr()));
  }

  void SetUsageMapEntry(const GURL& origin, int64 usage) {
    mock_service_.storage()->usage_map_[origin] = usage;
  }

  AppCacheQuotaClient* CreateClient() {
    return new AppCacheQuotaClient(&mock_service_);
  }

  void Call_NotifyAppCacheReady(AppCacheQuotaClient* client) {
    client->NotifyAppCacheReady();
  }

  void Call_NotifyAppCacheDestroyed(AppCacheQuotaClient* client) {
    client->NotifyAppCacheDestroyed();
  }

  void Call_OnQuotaManagerDestroyed(AppCacheQuotaClient* client) {
    client->OnQuotaManagerDestroyed();
  }

 protected:
  void OnGetOriginUsageComplete(int64 usage) {
    ++num_get_origin_usage_completions_;
    usage_ = usage;
  }

  void OnGetOriginsComplete(const std::set<GURL>& origins) {
    ++num_get_origins_completions_;
    origins_ = origins;
  }

  void OnDeleteOriginDataComplete(quota::QuotaStatusCode status) {
    ++num_delete_origins_completions_;
    delete_status_ = status;
  }

  base::MessageLoop message_loop_;
  int64 usage_;
  std::set<GURL> origins_;
  quota::QuotaStatusCode delete_status_;
  int num_get_origin_usage_completions_;
  int num_get_origins_completions_;
  int num_delete_origins_completions_;
  MockAppCacheService mock_service_;
  base::WeakPtrFactory<AppCacheQuotaClientTest> weak_factory_;
};


TEST_F(AppCacheQuotaClientTest, BasicCreateDestroy) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);
  Call_OnQuotaManagerDestroyed(client);
  Call_NotifyAppCacheDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, EmptyService) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);

  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kTemp));
  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));
  EXPECT_TRUE(GetOriginsForType(client, kTemp).empty());
  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
  EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty());
  EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty());
  EXPECT_EQ(quota::kQuotaStatusOk, DeleteOriginData(client, kTemp, kOriginA));
  EXPECT_EQ(quota::kQuotaStatusOk, DeleteOriginData(client, kPerm, kOriginA));

  Call_NotifyAppCacheDestroyed(client);
  Call_OnQuotaManagerDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, NoService) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);
  Call_NotifyAppCacheDestroyed(client);

  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kTemp));
  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));
  EXPECT_TRUE(GetOriginsForType(client, kTemp).empty());
  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
  EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty());
  EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty());
  EXPECT_EQ(quota::kQuotaErrorAbort,
            DeleteOriginData(client, kTemp, kOriginA));
  EXPECT_EQ(quota::kQuotaErrorAbort,
            DeleteOriginData(client, kPerm, kOriginA));

  Call_OnQuotaManagerDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, GetOriginUsage) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);

  SetUsageMapEntry(kOriginA, 1000);
  EXPECT_EQ(1000, GetOriginUsage(client, kOriginA, kTemp));
  EXPECT_EQ(0, GetOriginUsage(client, kOriginA, kPerm));

  Call_NotifyAppCacheDestroyed(client);
  Call_OnQuotaManagerDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, GetOriginsForHost) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);

  EXPECT_EQ(kOriginA.host(), kOriginB.host());
  EXPECT_NE(kOriginA.host(), kOriginOther.host());

  std::set<GURL> origins = GetOriginsForHost(client, kTemp, kOriginA.host());
  EXPECT_TRUE(origins.empty());

  SetUsageMapEntry(kOriginA, 1000);
  SetUsageMapEntry(kOriginB, 10);
  SetUsageMapEntry(kOriginOther, 500);

  origins = GetOriginsForHost(client, kTemp, kOriginA.host());
  EXPECT_EQ(2ul, origins.size());
  EXPECT_TRUE(origins.find(kOriginA) != origins.end());
  EXPECT_TRUE(origins.find(kOriginB) != origins.end());

  origins = GetOriginsForHost(client, kTemp, kOriginOther.host());
  EXPECT_EQ(1ul, origins.size());
  EXPECT_TRUE(origins.find(kOriginOther) != origins.end());

  origins = GetOriginsForHost(client, kPerm, kOriginA.host());
  EXPECT_TRUE(origins.empty());

  Call_NotifyAppCacheDestroyed(client);
  Call_OnQuotaManagerDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, GetOriginsForType) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);

  EXPECT_TRUE(GetOriginsForType(client, kTemp).empty());
  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());

  SetUsageMapEntry(kOriginA, 1000);
  SetUsageMapEntry(kOriginB, 10);

  std::set<GURL> origins = GetOriginsForType(client, kTemp);
  EXPECT_EQ(2ul, origins.size());
  EXPECT_TRUE(origins.find(kOriginA) != origins.end());
  EXPECT_TRUE(origins.find(kOriginB) != origins.end());

  EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());

  Call_NotifyAppCacheDestroyed(client);
  Call_OnQuotaManagerDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, DeleteOriginData) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);

  // Perm deletions are short circuited in the Client and
  // should not reach the AppCacheService.
  EXPECT_EQ(quota::kQuotaStatusOk,
            DeleteOriginData(client, kPerm, kOriginA));
  EXPECT_EQ(0, mock_service_.delete_called_count());

  EXPECT_EQ(quota::kQuotaStatusOk,
            DeleteOriginData(client, kTemp, kOriginA));
  EXPECT_EQ(1, mock_service_.delete_called_count());

  mock_service_.set_mock_delete_appcaches_for_origin_result(
      net::ERR_ABORTED);
  EXPECT_EQ(quota::kQuotaErrorAbort,
            DeleteOriginData(client, kTemp, kOriginA));
  EXPECT_EQ(2, mock_service_.delete_called_count());

  Call_OnQuotaManagerDestroyed(client);
  Call_NotifyAppCacheDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, PendingRequests) {
  AppCacheQuotaClient* client = CreateClient();

  SetUsageMapEntry(kOriginA, 1000);
  SetUsageMapEntry(kOriginB, 10);
  SetUsageMapEntry(kOriginOther, 500);

  // Queue up some reqeusts.
  AsyncGetOriginUsage(client, kOriginA, kPerm);
  AsyncGetOriginUsage(client, kOriginB, kTemp);
  AsyncGetOriginsForType(client, kPerm);
  AsyncGetOriginsForType(client, kTemp);
  AsyncGetOriginsForHost(client, kTemp, kOriginA.host());
  AsyncGetOriginsForHost(client, kTemp, kOriginOther.host());
  AsyncDeleteOriginData(client, kTemp, kOriginA);
  AsyncDeleteOriginData(client, kPerm, kOriginA);
  AsyncDeleteOriginData(client, kTemp, kOriginB);

  EXPECT_EQ(0, num_get_origin_usage_completions_);
  EXPECT_EQ(0, num_get_origins_completions_);
  EXPECT_EQ(0, num_delete_origins_completions_);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(0, num_get_origin_usage_completions_);
  EXPECT_EQ(0, num_get_origins_completions_);
  EXPECT_EQ(0, num_delete_origins_completions_);

  // Pending requests should get serviced when the appcache is ready.
  Call_NotifyAppCacheReady(client);
  EXPECT_EQ(2, num_get_origin_usage_completions_);
  EXPECT_EQ(4, num_get_origins_completions_);
  EXPECT_EQ(0, num_delete_origins_completions_);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(3, num_delete_origins_completions_);  // deletes are really async

  // They should be serviced in order requested.
  EXPECT_EQ(10, usage_);
  EXPECT_EQ(1ul, origins_.size());
  EXPECT_TRUE(origins_.find(kOriginOther) != origins_.end());

  Call_NotifyAppCacheDestroyed(client);
  Call_OnQuotaManagerDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, DestroyServiceWithPending) {
  AppCacheQuotaClient* client = CreateClient();

  SetUsageMapEntry(kOriginA, 1000);
  SetUsageMapEntry(kOriginB, 10);
  SetUsageMapEntry(kOriginOther, 500);

  // Queue up some reqeusts prior to being ready.
  AsyncGetOriginUsage(client, kOriginA, kPerm);
  AsyncGetOriginUsage(client, kOriginB, kTemp);
  AsyncGetOriginsForType(client, kPerm);
  AsyncGetOriginsForType(client, kTemp);
  AsyncGetOriginsForHost(client, kTemp, kOriginA.host());
  AsyncGetOriginsForHost(client, kTemp, kOriginOther.host());
  AsyncDeleteOriginData(client, kTemp, kOriginA);
  AsyncDeleteOriginData(client, kPerm, kOriginA);
  AsyncDeleteOriginData(client, kTemp, kOriginB);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(0, num_get_origin_usage_completions_);
  EXPECT_EQ(0, num_get_origins_completions_);
  EXPECT_EQ(0, num_delete_origins_completions_);

  // Kill the service.
  Call_NotifyAppCacheDestroyed(client);

  // All should have been aborted and called completion.
  EXPECT_EQ(2, num_get_origin_usage_completions_);
  EXPECT_EQ(4, num_get_origins_completions_);
  EXPECT_EQ(3, num_delete_origins_completions_);
  EXPECT_EQ(0, usage_);
  EXPECT_TRUE(origins_.empty());
  EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_);

  Call_OnQuotaManagerDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, DestroyQuotaManagerWithPending) {
  AppCacheQuotaClient* client = CreateClient();

  SetUsageMapEntry(kOriginA, 1000);
  SetUsageMapEntry(kOriginB, 10);
  SetUsageMapEntry(kOriginOther, 500);

  // Queue up some reqeusts prior to being ready.
  AsyncGetOriginUsage(client, kOriginA, kPerm);
  AsyncGetOriginUsage(client, kOriginB, kTemp);
  AsyncGetOriginsForType(client, kPerm);
  AsyncGetOriginsForType(client, kTemp);
  AsyncGetOriginsForHost(client, kTemp, kOriginA.host());
  AsyncGetOriginsForHost(client, kTemp, kOriginOther.host());
  AsyncDeleteOriginData(client, kTemp, kOriginA);
  AsyncDeleteOriginData(client, kPerm, kOriginA);
  AsyncDeleteOriginData(client, kTemp, kOriginB);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(0, num_get_origin_usage_completions_);
  EXPECT_EQ(0, num_get_origins_completions_);
  EXPECT_EQ(0, num_delete_origins_completions_);

  // Kill the quota manager.
  Call_OnQuotaManagerDestroyed(client);
  Call_NotifyAppCacheReady(client);

  // Callbacks should be deleted and not called.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(0, num_get_origin_usage_completions_);
  EXPECT_EQ(0, num_get_origins_completions_);
  EXPECT_EQ(0, num_delete_origins_completions_);

  Call_NotifyAppCacheDestroyed(client);
}

TEST_F(AppCacheQuotaClientTest, DestroyWithDeleteInProgress) {
  AppCacheQuotaClient* client = CreateClient();
  Call_NotifyAppCacheReady(client);

  // Start an async delete.
  AsyncDeleteOriginData(client, kTemp, kOriginB);
  EXPECT_EQ(0, num_delete_origins_completions_);

  // Kill the service.
  Call_NotifyAppCacheDestroyed(client);

  // Should have been aborted.
  EXPECT_EQ(1, num_delete_origins_completions_);
  EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_);

  // A real completion callback from the service should
  // be dropped if it comes in after NotifyAppCacheDestroyed.
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, num_delete_origins_completions_);
  EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_);

  Call_OnQuotaManagerDestroyed(client);
}

}  // namespace appcache

/* [<][>][^][v][top][bottom][index][help] */