Chromium Code Reviews| Index: chrome/browser/policy/cloud/cloud_external_data_manager_base_unittest.cc |
| diff --git a/chrome/browser/policy/cloud/cloud_external_data_manager_base_unittest.cc b/chrome/browser/policy/cloud/cloud_external_data_manager_base_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b56a9889d35bdfac934bf775b242d7c046879728 |
| --- /dev/null |
| +++ b/chrome/browser/policy/cloud/cloud_external_data_manager_base_unittest.cc |
| @@ -0,0 +1,753 @@ |
| +// 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 "chrome/browser/policy/cloud/cloud_external_data_manager_base.h" |
| + |
| +#include <map> |
| +#include <string> |
| + |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| +#include "base/files/scoped_temp_dir.h" |
| +#include "base/message_loop/message_loop_proxy.h" |
| +#include "base/run_loop.h" |
| +#include "base/sequenced_task_runner.h" |
| +#include "base/sha1.h" |
| +#include "base/stl_util.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/policy/cloud/cloud_external_data_store.h" |
| +#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h" |
| +#include "chrome/browser/policy/cloud/resource_cache.h" |
| +#include "chrome/browser/policy/external_data_fetcher.h" |
| +#include "chrome/browser/policy/policy_map.h" |
| +#include "chrome/browser/policy/policy_types.h" |
| +#include "content/public/test/test_browser_thread_bundle.h" |
| +#include "net/url_request/test_url_fetcher_factory.h" |
| +#include "net/url_request/url_fetcher.h" |
| +#include "net/url_request/url_fetcher_delegate.h" |
| +#include "net/url_request/url_fetcher_factory.h" |
| +#include "net/url_request/url_request_test_util.h" |
| +#include "policy/policy_constants.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "url/gurl.h" |
| + |
| +namespace policy { |
| + |
| +namespace { |
| + |
| +// A string policy. |
| +const char kStringPolicy[] = "StringPolicy"; |
| +// A policy that may reference up to 10 bytes of external data. |
| +const char k10BytePolicy[] = "10BytePolicy"; |
| +// A policy that may reference up to 20 bytes of external data. |
| +const char k20BytePolicy[] = "20BytePolicy"; |
| +// A nonexistent policy. |
| +const char kUnknownPolicy[] = "UnknownPolicy"; |
| + |
| +const char k10BytePolicyURL[] = "http://localhost/10_bytes"; |
| +const char k20BytePolicyURL[] = "http://localhost/20_bytes"; |
| + |
| +const char k10ByteData[] = "10 bytes.."; |
| +const char k20ByteData[] = "20 bytes............"; |
| + |
| +const PolicyDefinitionList::Entry kPolicyDefinitionListEntries[] = { |
| + { kStringPolicy, base::Value::TYPE_STRING, false, 1, 0 }, |
| + { k10BytePolicy, base::Value::TYPE_DICTIONARY, false, 2, 10 }, |
| + { k20BytePolicy, base::Value::TYPE_DICTIONARY, false, 3, 20 }, |
| +}; |
| + |
| +const PolicyDefinitionList kPolicyDefinitionList = { |
| + kPolicyDefinitionListEntries, |
| + kPolicyDefinitionListEntries + arraysize(kPolicyDefinitionListEntries), |
| +}; |
| + |
| +const char kCacheKey[] = "data"; |
| + |
| +class FetchAttemptBlockingURLFetcherFactory : public net::URLFetcherFactory { |
| + public: |
| + FetchAttemptBlockingURLFetcherFactory(); |
| + virtual ~FetchAttemptBlockingURLFetcherFactory(); |
| + |
| + bool GetFetchAttempted() const; |
| + void ClearFetchAttempted(); |
|
Joao da Silva
2013/07/19 11:15:15
IIUC this class is meant to prevent creation of fe
bartfab (slow)
2013/07/19 13:06:30
Done.
|
| + |
| + // net::URLFetcherFactory: |
| + virtual net::URLFetcher* CreateURLFetcher( |
| + int id, |
| + const GURL& url, |
| + net::URLFetcher::RequestType request_type, |
| + net::URLFetcherDelegate* delegate) OVERRIDE; |
| + |
| + private: |
| + bool fetch_attempted_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(FetchAttemptBlockingURLFetcherFactory); |
| +}; |
| + |
| +FetchAttemptBlockingURLFetcherFactory::FetchAttemptBlockingURLFetcherFactory() |
| + : fetch_attempted_(false) { |
| +} |
| + |
| +FetchAttemptBlockingURLFetcherFactory:: |
| + ~FetchAttemptBlockingURLFetcherFactory() { |
| +} |
| + |
| +bool FetchAttemptBlockingURLFetcherFactory::GetFetchAttempted() const { |
| + return fetch_attempted_; |
| +} |
| + |
| +void FetchAttemptBlockingURLFetcherFactory::ClearFetchAttempted() { |
| + fetch_attempted_ = false; |
| +} |
| + |
| +net::URLFetcher* FetchAttemptBlockingURLFetcherFactory::CreateURLFetcher( |
| + int id, |
| + const GURL& url, |
| + net::URLFetcher::RequestType request_type, |
| + net::URLFetcherDelegate* delegate) { |
| + fetch_attempted_ = true; |
| + return NULL; |
| +} |
| + |
| +} // namespace |
| + |
| +class CouldExternalDataManagerBaseTest : public testing::Test { |
| + protected: |
| + CouldExternalDataManagerBaseTest(); |
| + |
| + virtual void SetUp() OVERRIDE; |
| + virtual void TearDown() OVERRIDE; |
| + |
| + void SetUpExternalDataManager(); |
| + |
| + scoped_ptr<base::DictionaryValue> ConstructMetadata(const std::string& url, |
| + const std::string& hash); |
| + void SetExternalDataReference(const std::string& policy, |
| + scoped_ptr<base::DictionaryValue> metadata); |
| + |
| + ExternalDataFetcher::FetchCallback ConstructFetchCallback(int id); |
| + void ResetCallbackData(); |
| + |
| + void OnFetchDone(int id, scoped_ptr<std::string> data); |
| + |
| + void FetchAll(); |
| + |
| + content::TestBrowserThreadBundle thread_bundle_; |
| + |
| + base::ScopedTempDir temp_dir_; |
| + scoped_ptr<ResourceCache> resource_cache_; |
| + MockCloudPolicyStore cloud_policy_store_; |
| + scoped_refptr<net::TestURLRequestContextGetter> request_content_getter_; |
| + FetchAttemptBlockingURLFetcherFactory default_fetcher_factory_; |
| + net::FakeURLFetcherFactory fake_fetcher_factory_; |
| + |
| + scoped_ptr<CloudExternalDataManagerBase> external_data_manager_; |
| + |
| + std::map<int, std::string*> callback_data_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CouldExternalDataManagerBaseTest); |
| +}; |
| + |
| +CouldExternalDataManagerBaseTest::CouldExternalDataManagerBaseTest() |
| + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), |
| + fake_fetcher_factory_(&default_fetcher_factory_) { |
| +} |
| + |
| +void CouldExternalDataManagerBaseTest::SetUp() { |
| + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| + resource_cache_.reset(new ResourceCache(temp_dir_.path())); |
| + SetUpExternalDataManager(); |
| + |
| + // Set |kStringPolicy| to a string value. |
| + cloud_policy_store_.policy_map_.Set(kStringPolicy, |
| + POLICY_LEVEL_MANDATORY, |
| + POLICY_SCOPE_USER, |
| + new base::StringValue(std::string()), |
| + NULL); |
| + // Make |k10BytePolicy| reference 10 bytes of external data. |
| + SetExternalDataReference( |
| + k10BytePolicy, |
| + ConstructMetadata(k10BytePolicyURL, base::SHA1HashString(k10ByteData))); |
| + // Make |k20BytePolicy| reference 20 bytes of external data. |
| + SetExternalDataReference( |
| + k20BytePolicy, |
| + ConstructMetadata(k20BytePolicyURL, base::SHA1HashString(k20ByteData))); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + |
| + request_content_getter_ = new net::TestURLRequestContextGetter( |
| + base::MessageLoopProxy::current()); |
| +} |
| + |
| +void CouldExternalDataManagerBaseTest::TearDown() { |
| + ResetCallbackData(); |
| +} |
| + |
| +void CouldExternalDataManagerBaseTest::SetUpExternalDataManager() { |
| + external_data_manager_.reset(new CloudExternalDataManagerBase( |
| + &kPolicyDefinitionList, base::MessageLoopProxy::current())); |
| + external_data_manager_->SetExternalDataStore(make_scoped_ptr( |
| + new CloudExternalDataStore(kCacheKey, resource_cache_.get()))); |
| + external_data_manager_->SetPolicyStore(&cloud_policy_store_); |
| +} |
| + |
| +scoped_ptr<base::DictionaryValue> |
| + CouldExternalDataManagerBaseTest::ConstructMetadata( |
| + const std::string& url, |
| + const std::string& hash) { |
| + scoped_ptr<base::DictionaryValue> metadata(new base::DictionaryValue); |
| + metadata->SetStringWithoutPathExpansion("url", url); |
| + metadata->SetStringWithoutPathExpansion("hash", base::HexEncode(hash.c_str(), |
| + hash.size())); |
| + return metadata.Pass(); |
| +} |
| + |
| +void CouldExternalDataManagerBaseTest::SetExternalDataReference( |
| + const std::string& policy, |
| + scoped_ptr<base::DictionaryValue> metadata) { |
| + cloud_policy_store_.policy_map_.Set( |
| + policy, |
| + POLICY_LEVEL_MANDATORY, |
| + POLICY_SCOPE_USER, |
| + metadata.release(), |
| + new ExternalDataFetcher( |
| + external_data_manager_->weak_factory_.GetWeakPtr(), policy)); |
| +} |
| + |
| +ExternalDataFetcher::FetchCallback |
| +CouldExternalDataManagerBaseTest::ConstructFetchCallback(int id) { |
| + return base::Bind(&CouldExternalDataManagerBaseTest::OnFetchDone, |
| + base::Unretained(this), |
| + id); |
| +} |
| + |
| +void CouldExternalDataManagerBaseTest::ResetCallbackData() { |
| + STLDeleteValues(&callback_data_); |
| +} |
| + |
| +void CouldExternalDataManagerBaseTest::OnFetchDone( |
| + int id, |
| + scoped_ptr<std::string> data) { |
| + delete callback_data_[id]; |
| + callback_data_[id] = data.release(); |
| +} |
| + |
| +void CouldExternalDataManagerBaseTest::FetchAll() { |
| + external_data_manager_->FetchAll(); |
| +} |
| + |
| +// Verifies that when no valid external data reference has been set for a |
| +// policy, the attempt to retrieve the external data fails immediately. |
| +TEST_F(CouldExternalDataManagerBaseTest, FailToFetchInvalid) { |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Attempt to retrieve external data for |kStringPolicy|, which is a string |
| + // policy that does not reference any external data. |
| + external_data_manager_->Fetch(kStringPolicy, ConstructFetchCallback(0)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + EXPECT_TRUE(callback_data_.find(0) != callback_data_.end()); |
| + EXPECT_FALSE(callback_data_[0]); |
| + ResetCallbackData(); |
| + |
| + // Attempt to retrieve external data for |kUnknownPolicy|, which is not a |
| + // known policy. |
| + external_data_manager_->Fetch(kUnknownPolicy, ConstructFetchCallback(1)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + EXPECT_TRUE(callback_data_.find(1) != callback_data_.end()); |
| + EXPECT_FALSE(callback_data_[1]); |
| + ResetCallbackData(); |
| + |
| + // Set an invalid external data reference for |k10BytePolicy|. |
| + SetExternalDataReference(k10BytePolicy, |
| + ConstructMetadata(std::string(), std::string())); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + |
| + // Attempt to retrieve external data for |k10BytePolicy|, which now has an |
| + // invalid reference. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(2)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + EXPECT_TRUE(callback_data_.find(2) != callback_data_.end()); |
| + EXPECT_FALSE(callback_data_[2]); |
| + ResetCallbackData(); |
| +} |
| + |
| +// Verifies that external data referenced by a policy is downloaded and cached |
| +// when first requested. Subsequent requests are served from the cache without |
| +// further download attempts. |
| +TEST_F(CouldExternalDataManagerBaseTest, DownloadAndCache) { |
| + // Serve valid external data for |k10BytePolicy|. |
| + fake_fetcher_factory_.SetFakeResponse(k10BytePolicyURL, k10ByteData, true); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Retrieve external data for |k10BytePolicy|. Verify that a download happens |
| + // and the callback is invoked with the downloaded data. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[0]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[0]); |
| + ResetCallbackData(); |
| + |
| + // Stop serving external data for |k10BytePolicy|. |
| + fake_fetcher_factory_.ClearFakeResponses(); |
| + |
| + // Retrieve external data for |k10BytePolicy| again. Verify that no download |
| + // is attempted but the callback is still invoked with the expected data, |
| + // served from the cache. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(1)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[1]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[1]); |
| + ResetCallbackData(); |
| + |
| + // Explicitly tell the external_data_manager_ to not make any download |
| + // attempts. |
| + external_data_manager_->Disconnect(); |
| + |
| + // Retrieve external data for |k10BytePolicy| again. Verify that even though |
| + // downloads are not allowed, the callback is still invoked with the expected |
| + // data, served from the cache. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(2)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[2]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[2]); |
| + ResetCallbackData(); |
| + |
| + // Verify that the downloaded data is present in the cache. |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + std::string data; |
| + EXPECT_TRUE(CloudExternalDataStore(kCacheKey, resource_cache_.get()).Load( |
| + k10BytePolicy, base::SHA1HashString(k10ByteData), 10, &data)); |
| + EXPECT_EQ(k10ByteData, data); |
| +} |
| + |
| +// Verifies that a request to download and cache all external data referenced by |
| +// policies is carried out correctly. Subsequent requests for the data are |
| +// served from the cache without further download attempts. |
| +TEST_F(CouldExternalDataManagerBaseTest, DownloadAndCacheAll) { |
| + // Serve valid external data for |k10BytePolicy| and |k20BytePolicy|. |
| + fake_fetcher_factory_.SetFakeResponse(k10BytePolicyURL, k10ByteData, true); |
| + fake_fetcher_factory_.SetFakeResponse(k20BytePolicyURL, k20ByteData, true); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Request that external data referenced by all policies be downloaded. |
| + FetchAll(); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + |
| + // Stop serving external data for |k10BytePolicy| and |k20BytePolicy|. |
| + fake_fetcher_factory_.ClearFakeResponses(); |
| + |
| + // Retrieve external data for |k10BytePolicy| and |k20BytePolicy|. Verify that |
| + // no downloads are attempted but the callbacks are still invoked with the |
| + // expected data, served from the cache. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0)); |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(2u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[0]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[0]); |
| + ASSERT_TRUE(callback_data_[1]); |
| + EXPECT_EQ(k20ByteData, *callback_data_[1]); |
| + ResetCallbackData(); |
| + |
| + // Explicitly tell the external_data_manager_ to not make any download |
| + // attempts. |
| + external_data_manager_->Disconnect(); |
| + |
| + // Retrieve external data for |k10BytePolicy| and |k20BytePolicy|. Verify that |
| + // even though downloads are not allowed, the callbacks are still invoked with |
| + // the expected data, served from the cache. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(2)); |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(3)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(2u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[2]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[2]); |
| + ASSERT_TRUE(callback_data_[3]); |
| + EXPECT_EQ(k20ByteData, *callback_data_[3]); |
| + ResetCallbackData(); |
| + |
| + // Verify that the downloaded data is present in the cache. |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + CloudExternalDataStore cache(kCacheKey, resource_cache_.get()); |
| + std::string data; |
| + EXPECT_TRUE(cache.Load(k10BytePolicy, base::SHA1HashString(k10ByteData), 10, |
| + &data)); |
| + EXPECT_EQ(k10ByteData, data); |
| + EXPECT_TRUE(cache.Load(k20BytePolicy, base::SHA1HashString(k20ByteData), 20, |
| + &data)); |
| + EXPECT_EQ(k20ByteData, data); |
| +} |
| + |
| +// Verifies that when the external data referenced by a policy is not present in |
| +// the cache and downloads are not allowed, a request to retrieve the data is |
| +// enqueued and carried out when downloads become possible. |
| +TEST_F(CouldExternalDataManagerBaseTest, DownloadAfterConnect) { |
| + // Attempt to retrieve external data for |k10BytePolicy|. Verify that the |
| + // callback is not invoked as the request remains pending. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_TRUE(callback_data_.empty()); |
| + ResetCallbackData(); |
| + |
| + // Serve valid external data for |k10BytePolicy| and allow the |
| + // external_data_manager_ to perform downloads. |
| + fake_fetcher_factory_.SetFakeResponse(k10BytePolicyURL, k10ByteData, true); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Verify that a download happens and the callback is invoked with the |
| + // downloaded data. |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[0]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[0]); |
| + ResetCallbackData(); |
| +} |
| + |
| +// Verifies that when the external data referenced by a policy is not present in |
| +// the cache and cannot be downloaded at this time, a request to retrieve the |
| +// data is enqueued to be retried later. |
| +TEST_F(CouldExternalDataManagerBaseTest, DownloadError) { |
| + // Make attempts to download the external data for |k20BytePolicy| fail with |
| + // an error. |
| + fake_fetcher_factory_.SetFakeResponse(k20BytePolicyURL, std::string(), false); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Attempt to retrieve external data for |k20BytePolicy|. Verify that the |
| + // callback is not invoked as the download attempt fails and the request |
| + // remains pending. |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(0)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_TRUE(callback_data_.empty()); |
| + ResetCallbackData(); |
| + |
| + // Modify the external data reference for |k20BytePolicy|, allowing the |
| + // download to be retried immediately. |
| + SetExternalDataReference( |
| + k20BytePolicy, |
| + ConstructMetadata(k20BytePolicyURL, base::SHA1HashString(k10ByteData))); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + |
| + // Attempt to retrieve external data for |k20BytePolicy| again. Verify that |
| + // no callback is invoked still as the download attempt fails again and the |
| + // request remains pending. |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_TRUE(callback_data_.empty()); |
| + ResetCallbackData(); |
| + |
| + // Modify the external data reference for |k20BytePolicy|, allowing the |
| + // download to be retried immediately. |
| + SetExternalDataReference( |
| + k20BytePolicy, |
| + ConstructMetadata(k20BytePolicyURL, base::SHA1HashString(k20ByteData))); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + |
| + // Serve external data for |k20BytePolicy| that does not match the hash |
| + // specified in its current external data reference. |
| + fake_fetcher_factory_.SetFakeResponse(k20BytePolicyURL, k10ByteData, true); |
| + |
| + // Attempt to retrieve external data for |k20BytePolicy| again. Verify that |
| + // no callback is invoked still as the downloaded succeeds but returns data |
| + // that does not match the external data reference. |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(2)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_TRUE(callback_data_.empty()); |
| + ResetCallbackData(); |
| + |
| + // Modify the external data reference for |k20BytePolicy|, allowing the |
| + // download to be retried immediately. The external data reference now matches |
| + // the data being served. |
| + SetExternalDataReference( |
| + k20BytePolicy, |
| + ConstructMetadata(k20BytePolicyURL, base::SHA1HashString(k10ByteData))); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + |
| + // Attempt to retrieve external data for |k20BytePolicy| again. Verify that |
| + // the current callback and the three previously enqueued callbacks are |
| + // invoked with the downloaded data now. |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(3)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(4u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[0]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[0]); |
| + ASSERT_TRUE(callback_data_[1]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[1]); |
| + ASSERT_TRUE(callback_data_[2]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[2]); |
| + ASSERT_TRUE(callback_data_[3]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[3]); |
| + ResetCallbackData(); |
| +} |
| + |
| +// Verifies that when the external data referenced by a policy is present in the |
| +// cache, a request to retrieve it is served from the cache without any download |
| +// attempts. |
| +TEST_F(CouldExternalDataManagerBaseTest, LoadFromCache) { |
| + // Store valid external data for |k10BytePolicy| in the cache. |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_TRUE(CloudExternalDataStore(kCacheKey, resource_cache_.get()).Store( |
| + k10BytePolicy, base::SHA1HashString(k10ByteData), k10ByteData)); |
| + |
| + // Instantiate an external_data_manager_ that uses the primed cache. |
| + SetUpExternalDataManager(); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Retrieve external data for |k10BytePolicy|. Verify that no download is |
| + // attempted but the callback is still invoked with the expected data, served |
| + // from the cache. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[0]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[0]); |
| + ResetCallbackData(); |
| +} |
| + |
| +// Verifies that cache entries which do not correspond to the external data |
| +// referenced by any policy are pruned on startup. |
| +TEST_F(CouldExternalDataManagerBaseTest, PruneCacheOnStartup) { |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + scoped_ptr<CloudExternalDataStore> |
| + cache(new CloudExternalDataStore(kCacheKey, resource_cache_.get())); |
| + // Store valid external data for |k10BytePolicy| in the cache. |
| + EXPECT_TRUE(cache->Store(k10BytePolicy, |
| + base::SHA1HashString(k10ByteData), |
| + k10ByteData)); |
| + // Store external data for |k20BytePolicy| that does not match the hash in its |
| + // external data reference. |
| + EXPECT_TRUE(cache->Store(k20BytePolicy, |
| + base::SHA1HashString(k10ByteData), |
| + k10ByteData)); |
| + // Store external data for |kUnknownPolicy|, which is not a known policy and |
| + // therefore, cannot be referencing any external data. |
| + EXPECT_TRUE(cache->Store(kUnknownPolicy, |
| + base::SHA1HashString(k10ByteData), |
| + k10ByteData)); |
| + cache.reset(); |
| + |
| + // Instantiate and destroy an ExternalDataManager that uses the primed cache. |
| + SetUpExternalDataManager(); |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + cache.reset(new CloudExternalDataStore(kCacheKey, resource_cache_.get())); |
| + std::string data; |
| + // Verify that the valid external data for |k10BytePolicy| is still in the |
| + // cache. |
| + EXPECT_TRUE(cache->Load(k10BytePolicy, base::SHA1HashString(k10ByteData), |
| + 10, &data)); |
| + EXPECT_EQ(k10ByteData, data); |
| + // Verify that the external data for |k20BytePolicy| and |kUnknownPolicy| has |
| + // been pruned from the cache. |
| + EXPECT_FALSE(cache->Load(k20BytePolicy, base::SHA1HashString(k10ByteData), |
| + 20, &data)); |
| + EXPECT_FALSE(cache->Load(kUnknownPolicy, base::SHA1HashString(k10ByteData), |
| + 20, &data)); |
| +} |
| + |
| +// Verifies that when the external data referenced by a policy is present in the |
| +// cache and the reference changes, the old data is pruned from the cache. |
| +TEST_F(CouldExternalDataManagerBaseTest, PruneCacheOnChange) { |
| + // Store valid external data for |k20BytePolicy| in the cache. |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + scoped_ptr<CloudExternalDataStore> |
| + cache(new CloudExternalDataStore(kCacheKey, resource_cache_.get())); |
| + EXPECT_TRUE(cache->Store(k20BytePolicy, |
| + base::SHA1HashString(k20ByteData), |
| + k20ByteData)); |
| + cache.reset(); |
| + |
| + // Instantiate an ExternalDataManager that uses the primed cache. |
| + SetUpExternalDataManager(); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Modify the external data reference for |k20BytePolicy|. |
| + SetExternalDataReference( |
| + k20BytePolicy, |
| + ConstructMetadata(k20BytePolicyURL, base::SHA1HashString(k10ByteData))); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + |
| + // Verify that the old external data for |k20BytePolicy| has been pruned from |
| + // the cache. |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + cache.reset(new CloudExternalDataStore(kCacheKey, resource_cache_.get())); |
| + std::string data; |
| + EXPECT_FALSE(cache->Load(k20BytePolicy, base::SHA1HashString(k20ByteData), 20, |
| + &data)); |
| +} |
| + |
| +// Verifies that corrupt cache entries are detected and deleted when accessed. |
| +TEST_F(CouldExternalDataManagerBaseTest, CacheCorruption) { |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + scoped_ptr<CloudExternalDataStore> |
| + cache(new CloudExternalDataStore(kCacheKey, resource_cache_.get())); |
| + // Store external data for |k10BytePolicy| that exceeds the maximal external |
| + // data size allowed for that policy. |
| + EXPECT_TRUE(cache->Store(k10BytePolicy, |
| + base::SHA1HashString(k20ByteData), |
| + k20ByteData)); |
| + // Store external data for |k20BytePolicy| that is corrupted and does not |
| + // match the expected hash. |
| + EXPECT_TRUE(cache->Store(k20BytePolicy, |
| + base::SHA1HashString(k20ByteData), |
| + k10ByteData)); |
| + cache.reset(); |
| + |
| + SetUpExternalDataManager(); |
| + // Serve external data for |k10BytePolicy| that exceeds the maximal external |
| + // data size allowed for that policy. |
| + fake_fetcher_factory_.SetFakeResponse(k10BytePolicyURL, k20ByteData, true); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Modify the external data reference for |k10BytePolicy| to match the |
| + // external data being served. |
| + SetExternalDataReference( |
| + k10BytePolicy, |
| + ConstructMetadata(k10BytePolicyURL, base::SHA1HashString(k20ByteData))); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + |
| + // Retrieve external data for |k10BytePolicy|. Verify that the callback is |
| + // not invoked as the cached and downloaded external data exceed the maximal |
| + // size allowed for this policy and the request remains pending. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_TRUE(callback_data_.empty()); |
| + ResetCallbackData(); |
| + |
| + // Serve valid external data for |k20BytePolicy|. |
| + fake_fetcher_factory_.SetFakeResponse(k20BytePolicyURL, k20ByteData, true); |
| + |
| + // Retrieve external data for |k20BytePolicy|. Verify that the callback is |
| + // invoked with the valid downloaded data, not the invalid data in the cache. |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[1]); |
| + EXPECT_EQ(k20ByteData, *callback_data_[1]); |
| + ResetCallbackData(); |
| + |
| + external_data_manager_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + cache.reset(new CloudExternalDataStore(kCacheKey, resource_cache_.get())); |
| + std::string data; |
| + // Verify that the invalid external data for |k10BytePolicy| has been pruned |
| + // from the cache. Load() will return |false| in two cases: |
| + // 1) The cache entry for |k10BytePolicy| has been pruned. |
| + // 2) The cache entry for |k10BytePolicy| still exists but the cached data |
| + // does not match the expected hash or exceeds the maximum size allowed. |
| + // To test for the former, Load() is called with a maximum data size and hash |
| + // that would allow the data originally written to the cache to be loaded. |
| + // When this fails, it is certain that the original data is no longer present |
| + // in the cache. |
| + EXPECT_FALSE(cache->Load(k10BytePolicy, base::SHA1HashString(k20ByteData), 20, |
| + &data)); |
| + // Verify that the invalid external data for |k20BytePolicy| has been replaced |
| + // with the downloaded valid data in the cache. |
| + EXPECT_TRUE(cache->Load(k20BytePolicy, base::SHA1HashString(k20ByteData), 20, |
| + &data)); |
| + EXPECT_EQ(k20ByteData, data); |
| +} |
| + |
| +// Verifies that when the external data reference for a policy changes while a |
| +// download of the external data for that policy is pending, the download is |
| +// immediately retried using the new reference. |
| +TEST_F(CouldExternalDataManagerBaseTest, PolicyChangeWhileDownloadPending) { |
| + // Make attempts to download the external data for |k10BytePolicy| and |
| + // |k20BytePolicy| fail with an error. |
| + fake_fetcher_factory_.SetFakeResponse(k10BytePolicyURL, std::string(), false); |
| + fake_fetcher_factory_.SetFakeResponse(k20BytePolicyURL, std::string(), false); |
| + external_data_manager_->Connect(request_content_getter_); |
| + |
| + // Attempt to retrieve external data for |k10BytePolicy| and |k20BytePolicy|. |
| + // Verify that no callbacks are invoked as the download attempts fail and the |
| + // requests remain pending. |
| + external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0)); |
| + external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1)); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_TRUE(callback_data_.empty()); |
| + ResetCallbackData(); |
| + |
| + // Modify the external data reference for |k10BytePolicy| to be invalid. |
| + // Verify that the callback is invoked as the policy no longer has a valid |
| + // external data reference. |
| + cloud_policy_store_.policy_map_.Erase(k10BytePolicy); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + EXPECT_TRUE(callback_data_.find(0) != callback_data_.end()); |
| + EXPECT_FALSE(callback_data_[0]); |
| + ResetCallbackData(); |
| + |
| + // Serve valid external data for |k20BytePolicy|. |
| + fake_fetcher_factory_.ClearFakeResponses(); |
| + fake_fetcher_factory_.SetFakeResponse(k20BytePolicyURL, k10ByteData, true); |
| + |
| + // Modify the external data reference for |k20BytePolicy| to match the |
| + // external data now being served. Verify that the callback is invoked with |
| + // the downloaded data. |
| + SetExternalDataReference( |
| + k20BytePolicy, |
| + ConstructMetadata(k20BytePolicyURL, base::SHA1HashString(k10ByteData))); |
| + cloud_policy_store_.NotifyStoreLoaded(); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(default_fetcher_factory_.GetFetchAttempted()); |
| + default_fetcher_factory_.ClearFetchAttempted(); |
| + EXPECT_EQ(1u, callback_data_.size()); |
| + ASSERT_TRUE(callback_data_[1]); |
| + EXPECT_EQ(k10ByteData, *callback_data_[1]); |
| + ResetCallbackData(); |
| +} |
| + |
| +} // namespace policy |