Index: chrome/browser/browsing_data/storage_partition_http_cache_data_remover_browsertest.cc |
diff --git a/chrome/browser/browsing_data/storage_partition_http_cache_data_remover_browsertest.cc b/chrome/browser/browsing_data/storage_partition_http_cache_data_remover_browsertest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..df7b04cef4d1b6bc39b0eba615c11d57a230a04f |
--- /dev/null |
+++ b/chrome/browser/browsing_data/storage_partition_http_cache_data_remover_browsertest.cc |
@@ -0,0 +1,445 @@ |
+// Copyright (c) 2015 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/run_loop.h" |
+#include "base/threading/platform_thread.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/test/base/in_process_browser_test.h" |
+#include "components/browsing_data/storage_partition_http_cache_data_remover.h" |
+#include "content/public/browser/browser_context.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/storage_partition.h" |
+#include "net/disk_cache/disk_cache.h" |
+#include "net/http/http_cache.h" |
+#include "net/url_request/url_request_context.h" |
+#include "net/url_request/url_request_context_getter.h" |
+ |
+using browsing_data::StoragePartitionHttpCacheDataRemover; |
+using content::BrowserThread; |
+ |
+class StoragePartitionHttpCacheDataRemoverBrowserTest |
+ : public InProcessBrowserTest { |
+ public: |
+ // Initialization ------------------------------------------------------------ |
+ |
+ void SetUpOnMainThread() override { |
+ result_callback_ = base::Bind( |
+ &StoragePartitionHttpCacheDataRemoverBrowserTest::ResultCallback, |
+ base::Unretained(this)); |
+ removal_callback_ = base::Bind( |
+ &StoragePartitionHttpCacheDataRemoverBrowserTest::RemovalCallback, |
+ base::Unretained(this)); |
+ done_callback_ = base::Bind( |
+ &StoragePartitionHttpCacheDataRemoverBrowserTest::DoneCallback, |
+ base::Unretained(this)); |
+ remaining_tasks_ = 0; |
+ next_key_ = 0; |
+ |
+ partition_ = content::BrowserContext::GetDefaultStoragePartition( |
+ browser()->profile()); |
+ |
+ // Get the cache backends. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ InitializeCountingTest, |
+ base::Unretained(this))); |
+ WaitForTasksOnIOThread(); |
+ DCHECK(main_backend_); |
+ DCHECK(media_backend_); |
+ } |
+ |
+ void InitializeCountingTest() { |
+ net::URLRequestContextGetter* main_context; |
+ net::URLRequestContextGetter* media_context; |
+ |
+ main_context = partition_->GetURLRequestContext(); |
+ media_context = partition_->GetMediaURLRequestContext(); |
+ |
+ net::HttpCache* main_cache = main_context->GetURLRequestContext()-> |
+ http_transaction_factory()->GetCache(); |
+ net::HttpCache* media_cache = media_context->GetURLRequestContext()-> |
+ http_transaction_factory()->GetCache(); |
+ |
+ SetNumberOfWaitedTasks(2); |
+ WaitForCompletion(main_cache->GetBackend(&main_backend_, done_callback_)); |
+ WaitForCompletion(media_cache->GetBackend(&media_backend_, done_callback_)); |
+ } |
+ |
+ // Get a new remover instance. |
+ StoragePartitionHttpCacheDataRemover* GetNewRemover() { |
+ return GetNewRemoverForRange(base::Time(), base::Time::Max()); |
+ } |
+ |
+ StoragePartitionHttpCacheDataRemover* GetNewRemoverForRange( |
+ base::Time begin, base::Time end) { |
+ return StoragePartitionHttpCacheDataRemover::CreateForRange( |
+ partition_, begin, end); |
+ } |
+ |
+ // Waiting for the calculation and retrieving results on the UI thread, |
+ // or cache cleaning. -------------------------------------------------------- |
+ |
+ void WaitForResultOrRemoval() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ loop_.reset(new base::RunLoop()); |
+ loop_->Run(); |
+ } |
+ |
+ void ResultCallback(int64 result) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ if (loop_) |
+ loop_->Quit(); |
+ result_ = result; |
+ } |
+ |
+ void RemovalCallback() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ if (loop_) |
+ loop_->Quit(); |
+ } |
+ |
+ net::Int64CompletionCallback GetResultCallback() { |
+ return result_callback_; |
+ } |
+ |
+ base::Closure GetRemovalCallback() { |
+ return removal_callback_; |
+ } |
+ |
+ int64 GetResult() { |
+ return result_; |
+ } |
+ |
+ // Waiting for tasks to be done on IO thread. -------------------------------- |
+ |
+ void WaitForTasksOnIOThread() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ io_thread_loop_.reset(new base::RunLoop()); |
+ io_thread_loop_->Run(); |
+ } |
+ |
+ void SetNumberOfWaitedTasks(int count) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ remaining_tasks_ = count; |
+ } |
+ |
+ void WaitForCompletion(int value) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ if (value >= 0) { |
+ // We got the result immediately. |
+ DoneCallback(value); |
+ } else if (value == net::ERR_IO_PENDING) { |
+ // We need to wait for the callback. |
+ } else { |
+ // An error has occurred. |
+ NOTREACHED(); |
+ } |
+ } |
+ |
+ void DoneCallback(int value) { |
+ DCHECK_GE(value, 0); // Negative values represent error codes. |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ if (--remaining_tasks_ > 0) |
+ return; |
+ |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&base::RunLoop::Quit, |
+ base::Unretained(io_thread_loop_.get()))); |
+ } |
+ |
+ // Helpers. ------------------------------------------------------------------ |
+ |
+ void CreateCacheEntries(size_t main_count, size_t media_count) { |
+ entries_.resize(main_count + media_count); |
+ |
+ SetNumberOfWaitedTasks(main_count + media_count); |
+ for (size_t i = 0; i < main_count; ++i) { |
+ WaitForCompletion(main_backend_->CreateEntry( |
+ GetUniqueEntryKey(), &entries_[i], done_callback_)); |
+ } |
+ for (size_t i = main_count; i < main_count + media_count; ++i) { |
+ WaitForCompletion(media_backend_->CreateEntry( |
+ GetUniqueEntryKey(), &entries_[i], done_callback_)); |
+ } |
+ } |
+ |
+ void WriteDataToEntries(const std::vector<int>& sizes) { |
+ DCHECK_EQ(entries_.size(), sizes.size()); |
+ std::string data(*std::max_element(sizes.begin(), sizes.end()), ' '); |
+ scoped_refptr<net::StringIOBuffer> buffer = new net::StringIOBuffer(data); |
+ |
+ SetNumberOfWaitedTasks(entries_.size()); |
+ for (size_t i = 0; i < entries_.size(); ++i) { |
+ // Alternate between writing to the first and second stream to test that |
+ // we're taking all streams into account. |
+ WaitForCompletion(entries_[i]->WriteData( |
+ i % 2, 0, buffer.get(), sizes[i], done_callback_, true)); |
+ } |
+ } |
+ |
+ private: |
+ // Generates a unique key for a new cache entry. |
+ std::string GetUniqueEntryKey() { |
+ return std::to_string(next_key_++); |
+ } |
+ |
+ int next_key_; |
+ |
+ content::StoragePartition* partition_; |
+ disk_cache::Backend* main_backend_ = nullptr; |
+ disk_cache::Backend* media_backend_ = nullptr; |
+ |
+ // Shorthands for callback binding. |
+ base::Callback<void(int)> done_callback_; |
+ base::Closure removal_callback_; |
+ net::Int64CompletionCallback result_callback_; |
+ |
+ int64 result_; |
+ scoped_ptr<base::RunLoop> loop_; |
+ scoped_ptr<base::RunLoop> io_thread_loop_; |
+ |
+ std::vector<disk_cache::Entry*> entries_; |
+ int remaining_tasks_; |
+}; |
+ |
+// Test that the size of empty cache is computed as 0. |
+IN_PROC_BROWSER_TEST_F( |
+ StoragePartitionHttpCacheDataRemoverBrowserTest, Empty) { |
+ // Calculate the size of the empty caches. The result should be 0. |
+ GetNewRemover()->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 0 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+} |
+ |
+// Test that StoragePartitionHttpCacheDataRemover correctly counts the total |
+// size of items in the main and media cache. |
+IN_PROC_BROWSER_TEST_F( |
+ StoragePartitionHttpCacheDataRemoverBrowserTest, Counting) { |
+ // Create 5 entries and write 23 bytes of data, distributed to both caches, |
+ // different entries, and different streams within them. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ CreateCacheEntries, |
+ base::Unretained(this), |
+ 3, 2)); |
+ WaitForTasksOnIOThread(); |
+ |
+ std::vector<int> data; |
+ data.push_back(10); |
+ data.push_back(3); |
+ data.push_back(4); |
+ data.push_back(1); |
+ data.push_back(5); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ WriteDataToEntries, |
+ base::Unretained(this), |
+ data)); |
+ WaitForTasksOnIOThread(); |
+ |
+ // Calculate the size of the caches now. The result should be 23. |
+ // TODO(msramek): Change the test to "EXPECT_EQ(23, GetResult());" as soon as |
+ // the size calculation is implemented for memory and simple cache backends. |
+ GetNewRemover()->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 23 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+} |
+ |
+// Test that StoragePartitionHttpCacheDataRemover correctly recognizes the cache |
+// to be empty when it was populated and cleared again. |
+IN_PROC_BROWSER_TEST_F( |
+ StoragePartitionHttpCacheDataRemoverBrowserTest, PopulatedAndCleared) { |
+ // Write data to both caches. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ CreateCacheEntries, |
+ base::Unretained(this), |
+ 1, 2)); |
+ WaitForTasksOnIOThread(); |
+ |
+ std::vector<int> data; |
+ data.push_back(10000); |
+ data.push_back(12345); |
+ data.push_back(20000); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ WriteDataToEntries, |
+ base::Unretained(this), |
+ data)); |
+ WaitForTasksOnIOThread(); |
+ |
+ // Clear both caches. |
+ GetNewRemover()->Remove(GetRemovalCallback()); |
+ WaitForResultOrRemoval(); |
+ |
+ // Calculate the size of the caches. The result should be 0. |
+ // TODO(msramek): Change the test to "EXPECT_EQ(0, GetResult());" as soon as |
+ // the size calculation is implemented for memory and simple cache backends. |
+ GetNewRemover()->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 0 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+} |
+ |
+// Test that StoragePartitionHttpCacheDataRemover correctly counts the cache |
+// size when data are incrementally added. |
+IN_PROC_BROWSER_TEST_F( |
+ StoragePartitionHttpCacheDataRemoverBrowserTest, Incremental) { |
+ // Write data to both caches. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ CreateCacheEntries, |
+ base::Unretained(this), |
+ 1, 2)); |
+ WaitForTasksOnIOThread(); |
+ |
+ std::vector<int> data; |
+ data.push_back(5); |
+ data.push_back(7); |
+ data.push_back(9); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ WriteDataToEntries, |
+ base::Unretained(this), |
+ data)); |
+ WaitForTasksOnIOThread(); |
+ |
+ // The size should be 21. |
+ // TODO(msramek): Change the test to "EXPECT_EQ(21, GetResult());" as soon as |
+ // the size calculation is implemented for memory and simple cache backends. |
+ GetNewRemover()->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 21 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+ |
+ // Create a new batch of entries and write more data. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ CreateCacheEntries, |
+ base::Unretained(this), |
+ 4, 3)); |
+ WaitForTasksOnIOThread(); |
+ |
+ data.clear(); |
+ data.push_back(0); |
+ data.push_back(1); |
+ data.push_back(1); |
+ data.push_back(8); |
+ data.push_back(9); |
+ data.push_back(9); |
+ data.push_back(9); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ WriteDataToEntries, |
+ base::Unretained(this), |
+ data)); |
+ WaitForTasksOnIOThread(); |
+ |
+ // The size should be 58. |
+ // TODO(msramek): Change the test to "EXPECT_EQ(58, GetResult());" as soon as |
+ // the size calculation is implemented for memory and simple cache backends. |
+ GetNewRemover()->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 58 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+ |
+ // Update the entries from the last batch with new values. |
+ data.clear(); |
+ data.push_back(1); |
+ data.push_back(2); |
+ data.push_back(3); |
+ data.push_back(4); |
+ data.push_back(5); |
+ data.push_back(6); |
+ data.push_back(7); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ WriteDataToEntries, |
+ base::Unretained(this), |
+ data)); |
+ WaitForTasksOnIOThread(); |
+ |
+ // The size should now be 49. |
+ // TODO(msramek): Change the test to "EXPECT_EQ(49, GetResult());" as soon as |
+ // the size calculation is implemented for memory and simple cache backends. |
+ GetNewRemover()->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 49 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+} |
+ |
+IN_PROC_BROWSER_TEST_F( |
+ StoragePartitionHttpCacheDataRemoverBrowserTest, TimePeriod) { |
+ // Write a batch of entries. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ CreateCacheEntries, |
+ base::Unretained(this), |
+ 2, 2)); |
+ WaitForTasksOnIOThread(); |
+ |
+ std::vector<int> data; |
+ data.push_back(7); |
+ data.push_back(2); |
+ data.push_back(5); |
+ data.push_back(3); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ WriteDataToEntries, |
+ base::Unretained(this), |
+ data)); |
+ WaitForTasksOnIOThread(); |
+ |
+ // Skip at least a millisecond. Since time ranges are half-closed intervals, |
+ // |threshold| must be strictly greater than timestamps of any previous entry. |
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); |
+ base::Time threshold = base::Time::Now(); |
+ |
+ // Write another batch of entries. |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ CreateCacheEntries, |
+ base::Unretained(this), |
+ 1, 2)); |
+ WaitForTasksOnIOThread(); |
+ |
+ data.clear(); |
+ data.push_back(1); |
+ data.push_back(6); |
+ data.push_back(4); |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&StoragePartitionHttpCacheDataRemoverBrowserTest:: |
+ WriteDataToEntries, |
+ base::Unretained(this), |
+ data)); |
+ WaitForTasksOnIOThread(); |
+ |
+ // Count the entries added before the threshold. The result should be 17. |
+ // TODO(msramek): Change the test to "EXPECT_EQ(17, GetResult());" as soon as |
+ // the size calculation is implemented for memory and simple cache backends. |
+ GetNewRemoverForRange(base::Time(), threshold)->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 17 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+ |
+ // Count the entries added after the threshold. The result should be 11. |
+ // TODO(msramek): Change the test to "EXPECT_EQ(11, GetResult());" as soon as |
+ // the size calculation is implemented for memory and simple cache backends. |
+ GetNewRemoverForRange( |
+ threshold, base::Time::Now())->Count(GetResultCallback()); |
+ WaitForResultOrRemoval(); |
+ EXPECT_TRUE(GetResult() == 11 || GetResult() == net::ERR_NOT_IMPLEMENTED); |
+} |