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..3bdb2197a977a7ba440fa5832359e4ea826e90a1 |
--- /dev/null |
+++ b/chrome/browser/policy/cloud/cloud_external_data_manager_base_unittest.cc |
@@ -0,0 +1,701 @@ |
+// 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_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"; |
+ |
+// A variant of net::FakeURLFetcherFactory that makes it an error to request a |
+// fetcher for an unknown URL. |
+class FakeURLFetcherFactory : public net::FakeURLFetcherFactory { |
+ public: |
+ FakeURLFetcherFactory(); |
+ virtual ~FakeURLFetcherFactory(); |
+ |
+ // net::FakeURLFetcherFactory: |
+ virtual net::URLFetcher* CreateURLFetcher( |
+ int id, |
+ const GURL& url, |
+ net::URLFetcher::RequestType request_type, |
+ net::URLFetcherDelegate* delegate) OVERRIDE; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(FakeURLFetcherFactory); |
+}; |
+ |
+FakeURLFetcherFactory::FakeURLFetcherFactory() |
+ : net::FakeURLFetcherFactory(NULL) { |
+} |
+ |
+FakeURLFetcherFactory::~FakeURLFetcherFactory() { |
+} |
+ |
+net::URLFetcher* FakeURLFetcherFactory::CreateURLFetcher( |
+ int id, |
+ const GURL& url, |
+ net::URLFetcher::RequestType request_type, |
+ net::URLFetcherDelegate* delegate) { |
+ net::URLFetcher* fetcher = net::FakeURLFetcherFactory::CreateURLFetcher( |
+ id, url, request_type, delegate); |
+ EXPECT_TRUE(fetcher); |
+ return fetcher; |
+} |
+ |
+} // 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_; |
+ FakeURLFetcherFactory 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) { |
+} |
+ |
+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() { |
+ base::RunLoop().RunUntilIdle(); |
+ 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_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_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_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|. |
+ 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_EQ(1u, callback_data_.size()); |
+ ASSERT_TRUE(callback_data_[0]); |
+ EXPECT_EQ(k10ByteData, *callback_data_[0]); |
+ ResetCallbackData(); |
+ |
+ // Stop serving external data for |k10BytePolicy|. |
+ 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_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_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|. |
+ fetcher_factory_.SetFakeResponse(k10BytePolicyURL, k10ByteData, true); |
+ 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(); |
+ |
+ // Stop serving external data for |k10BytePolicy| and |k20BytePolicy|. |
+ 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_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_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. |
+ 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_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. |
+ 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_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_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. |
+ 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_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_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_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. |
+ 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_TRUE(callback_data_.empty()); |
+ ResetCallbackData(); |
+ |
+ // Serve valid external data for |k20BytePolicy|. |
+ 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_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. |
+ fetcher_factory_.SetFakeResponse(k10BytePolicyURL, std::string(), false); |
+ 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_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_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|. |
+ fetcher_factory_.ClearFakeResponses(); |
+ 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_EQ(1u, callback_data_.size()); |
+ ASSERT_TRUE(callback_data_[1]); |
+ EXPECT_EQ(k10ByteData, *callback_data_[1]); |
+ ResetCallbackData(); |
+} |
+ |
+} // namespace policy |