Home | History | Annotate | Download | only in policy
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
      6 
      7 #include <map>
      8 #include <string>
      9 
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/files/scoped_temp_dir.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/message_loop/message_loop_proxy.h"
     15 #include "base/run_loop.h"
     16 #include "base/stl_util.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "base/test/test_simple_task_runner.h"
     19 #include "base/values.h"
     20 #include "chrome/browser/chromeos/policy/cloud_external_data_store.h"
     21 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
     22 #include "components/policy/core/common/cloud/resource_cache.h"
     23 #include "components/policy/core/common/external_data_fetcher.h"
     24 #include "components/policy/core/common/policy_map.h"
     25 #include "components/policy/core/common/policy_test_utils.h"
     26 #include "components/policy/core/common/policy_types.h"
     27 #include "crypto/sha2.h"
     28 #include "net/http/http_status_code.h"
     29 #include "net/url_request/test_url_fetcher_factory.h"
     30 #include "net/url_request/url_fetcher.h"
     31 #include "net/url_request/url_fetcher_delegate.h"
     32 #include "net/url_request/url_request_status.h"
     33 #include "net/url_request/url_request_test_util.h"
     34 #include "testing/gtest/include/gtest/gtest.h"
     35 #include "url/gurl.h"
     36 
     37 namespace policy {
     38 
     39 namespace {
     40 
     41 // A string policy.
     42 const char kStringPolicy[] = "StringPolicy";
     43 // A policy that may reference up to 10 bytes of external data.
     44 const char k10BytePolicy[] = "10BytePolicy";
     45 // A policy that may reference up to 20 bytes of external data.
     46 const char k20BytePolicy[] = "20BytePolicy";
     47 // A nonexistent policy.
     48 const char kUnknownPolicy[] = "UnknownPolicy";
     49 
     50 const char k10BytePolicyURL[] = "http://localhost/10_bytes";
     51 const char k20BytePolicyURL[] = "http://localhost/20_bytes";
     52 
     53 const char k10ByteData[] = "10 bytes..";
     54 const char k20ByteData[] = "20 bytes............";
     55 
     56 const PolicyDetails kPolicyDetails[] = {
     57 //  is_deprecated  is_device_policy  id    max_external_data_size
     58   { false,         false,             1,                        0 },
     59   { false,         false,             2,                       10 },
     60   { false,         false,             3,                       20 },
     61 };
     62 
     63 const char kCacheKey[] = "data";
     64 
     65 // A variant of net::FakeURLFetcherFactory that makes it an error to request a
     66 // fetcher for an unknown URL.
     67 class FakeURLFetcherFactory : public net::FakeURLFetcherFactory {
     68  public:
     69   FakeURLFetcherFactory();
     70   virtual ~FakeURLFetcherFactory();
     71 
     72   // net::FakeURLFetcherFactory:
     73   virtual net::URLFetcher* CreateURLFetcher(
     74       int id,
     75       const GURL& url,
     76       net::URLFetcher::RequestType request_type,
     77       net::URLFetcherDelegate* delegate) OVERRIDE;
     78 
     79  private:
     80   DISALLOW_COPY_AND_ASSIGN(FakeURLFetcherFactory);
     81 };
     82 
     83 FakeURLFetcherFactory::FakeURLFetcherFactory()
     84     : net::FakeURLFetcherFactory(NULL) {
     85 }
     86 
     87 FakeURLFetcherFactory::~FakeURLFetcherFactory() {
     88 }
     89 
     90 net::URLFetcher* FakeURLFetcherFactory::CreateURLFetcher(
     91     int id,
     92     const GURL& url,
     93     net::URLFetcher::RequestType request_type,
     94     net::URLFetcherDelegate* delegate) {
     95   net::URLFetcher* fetcher = net::FakeURLFetcherFactory::CreateURLFetcher(
     96       id, url, request_type, delegate);
     97   EXPECT_TRUE(fetcher);
     98   return fetcher;
     99 }
    100 
    101 }  // namespace
    102 
    103 class CloudExternalDataManagerBaseTest : public testing::Test {
    104  protected:
    105   CloudExternalDataManagerBaseTest();
    106 
    107   virtual void SetUp() OVERRIDE;
    108   virtual void TearDown() OVERRIDE;
    109 
    110   void SetUpExternalDataManager();
    111 
    112   scoped_ptr<base::DictionaryValue> ConstructMetadata(const std::string& url,
    113                                                       const std::string& hash);
    114   void SetExternalDataReference(const std::string& policy,
    115                                 scoped_ptr<base::DictionaryValue> metadata);
    116 
    117   ExternalDataFetcher::FetchCallback ConstructFetchCallback(int id);
    118   void ResetCallbackData();
    119 
    120   void OnFetchDone(int id, scoped_ptr<std::string> data);
    121 
    122   void FetchAll();
    123 
    124   void SetFakeResponse(const std::string& url,
    125                        const std::string& repsonse_data,
    126                        net::HttpStatusCode response_code,
    127                        net::URLRequestStatus::Status status);
    128 
    129   base::MessageLoop message_loop_;
    130   base::ScopedTempDir temp_dir_;
    131   scoped_ptr<ResourceCache> resource_cache_;
    132   MockCloudPolicyStore cloud_policy_store_;
    133   scoped_refptr<net::TestURLRequestContextGetter> request_content_getter_;
    134   FakeURLFetcherFactory fetcher_factory_;
    135 
    136   scoped_ptr<CloudExternalDataManagerBase> external_data_manager_;
    137 
    138   std::map<int, std::string*> callback_data_;
    139   PolicyDetailsMap policy_details_;
    140 
    141   DISALLOW_COPY_AND_ASSIGN(CloudExternalDataManagerBaseTest);
    142 };
    143 
    144 CloudExternalDataManagerBaseTest::CloudExternalDataManagerBaseTest() {
    145 }
    146 
    147 void CloudExternalDataManagerBaseTest::SetUp() {
    148   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    149   resource_cache_.reset(new ResourceCache(temp_dir_.path(),
    150                                           message_loop_.message_loop_proxy()));
    151   SetUpExternalDataManager();
    152 
    153   // Set |kStringPolicy| to a string value.
    154   cloud_policy_store_.policy_map_.Set(kStringPolicy,
    155                                       POLICY_LEVEL_MANDATORY,
    156                                       POLICY_SCOPE_USER,
    157                                       new base::StringValue(std::string()),
    158                                       NULL);
    159   // Make |k10BytePolicy| reference 10 bytes of external data.
    160   SetExternalDataReference(
    161       k10BytePolicy,
    162       ConstructMetadata(k10BytePolicyURL,
    163                         crypto::SHA256HashString(k10ByteData)));
    164   // Make |k20BytePolicy| reference 20 bytes of external data.
    165   SetExternalDataReference(
    166       k20BytePolicy,
    167       ConstructMetadata(k20BytePolicyURL,
    168                         crypto::SHA256HashString(k20ByteData)));
    169   cloud_policy_store_.NotifyStoreLoaded();
    170 
    171   request_content_getter_ = new net::TestURLRequestContextGetter(
    172       base::MessageLoopProxy::current());
    173 
    174   policy_details_.SetDetails(kStringPolicy, &kPolicyDetails[0]);
    175   policy_details_.SetDetails(k10BytePolicy, &kPolicyDetails[1]);
    176   policy_details_.SetDetails(k20BytePolicy, &kPolicyDetails[2]);
    177 }
    178 
    179 void CloudExternalDataManagerBaseTest::TearDown() {
    180   external_data_manager_.reset();
    181   base::RunLoop().RunUntilIdle();
    182   ResetCallbackData();
    183 }
    184 
    185 void CloudExternalDataManagerBaseTest::SetUpExternalDataManager() {
    186   external_data_manager_.reset(new CloudExternalDataManagerBase(
    187       policy_details_.GetCallback(),
    188       message_loop_.message_loop_proxy(),
    189       message_loop_.message_loop_proxy()));
    190   external_data_manager_->SetExternalDataStore(make_scoped_ptr(
    191       new CloudExternalDataStore(kCacheKey,
    192                                  message_loop_.message_loop_proxy(),
    193                                  resource_cache_.get())));
    194   external_data_manager_->SetPolicyStore(&cloud_policy_store_);
    195 }
    196 
    197 scoped_ptr<base::DictionaryValue>
    198     CloudExternalDataManagerBaseTest::ConstructMetadata(
    199         const std::string& url,
    200         const std::string& hash) {
    201   scoped_ptr<base::DictionaryValue> metadata(new base::DictionaryValue);
    202   metadata->SetStringWithoutPathExpansion("url", url);
    203   metadata->SetStringWithoutPathExpansion("hash", base::HexEncode(hash.c_str(),
    204                                                                   hash.size()));
    205   return metadata.Pass();
    206 }
    207 
    208 void CloudExternalDataManagerBaseTest::SetExternalDataReference(
    209     const std::string& policy,
    210     scoped_ptr<base::DictionaryValue> metadata) {
    211   cloud_policy_store_.policy_map_.Set(
    212       policy,
    213       POLICY_LEVEL_MANDATORY,
    214       POLICY_SCOPE_USER,
    215       metadata.release(),
    216       new ExternalDataFetcher(
    217           external_data_manager_->weak_factory_.GetWeakPtr(), policy));
    218 }
    219 
    220 ExternalDataFetcher::FetchCallback
    221 CloudExternalDataManagerBaseTest::ConstructFetchCallback(int id) {
    222   return base::Bind(&CloudExternalDataManagerBaseTest::OnFetchDone,
    223                     base::Unretained(this),
    224                     id);
    225 }
    226 
    227 void CloudExternalDataManagerBaseTest::ResetCallbackData() {
    228   STLDeleteValues(&callback_data_);
    229 }
    230 
    231 void CloudExternalDataManagerBaseTest::OnFetchDone(
    232     int id,
    233     scoped_ptr<std::string> data) {
    234   delete callback_data_[id];
    235   callback_data_[id] = data.release();
    236 }
    237 
    238 void CloudExternalDataManagerBaseTest::FetchAll() {
    239   external_data_manager_->FetchAll();
    240 }
    241 
    242 void CloudExternalDataManagerBaseTest::SetFakeResponse(
    243     const std::string& url,
    244     const std::string& response_data,
    245     net::HttpStatusCode response_code,
    246     net::URLRequestStatus::Status status) {
    247   fetcher_factory_.SetFakeResponse(
    248       GURL(url), response_data, response_code, status);
    249 }
    250 
    251 // Verifies that when no valid external data reference has been set for a
    252 // policy, the attempt to retrieve the external data fails immediately.
    253 TEST_F(CloudExternalDataManagerBaseTest, FailToFetchInvalid) {
    254   external_data_manager_->Connect(request_content_getter_);
    255 
    256   // Attempt to retrieve external data for |kStringPolicy|, which is a string
    257   // policy that does not reference any external data.
    258   external_data_manager_->Fetch(kStringPolicy, ConstructFetchCallback(0));
    259   base::RunLoop().RunUntilIdle();
    260   EXPECT_EQ(1u, callback_data_.size());
    261   EXPECT_TRUE(callback_data_.find(0) != callback_data_.end());
    262   EXPECT_FALSE(callback_data_[0]);
    263   ResetCallbackData();
    264 
    265   // Attempt to retrieve external data for |kUnknownPolicy|, which is not a
    266   // known policy.
    267   external_data_manager_->Fetch(kUnknownPolicy, ConstructFetchCallback(1));
    268   base::RunLoop().RunUntilIdle();
    269   EXPECT_EQ(1u, callback_data_.size());
    270   EXPECT_TRUE(callback_data_.find(1) != callback_data_.end());
    271   EXPECT_FALSE(callback_data_[1]);
    272   ResetCallbackData();
    273 
    274   // Set an invalid external data reference for |k10BytePolicy|.
    275   SetExternalDataReference(k10BytePolicy,
    276                            ConstructMetadata(std::string(), std::string()));
    277   cloud_policy_store_.NotifyStoreLoaded();
    278 
    279   // Attempt to retrieve external data for |k10BytePolicy|, which now has an
    280   // invalid reference.
    281   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(2));
    282   base::RunLoop().RunUntilIdle();
    283   EXPECT_EQ(1u, callback_data_.size());
    284   EXPECT_TRUE(callback_data_.find(2) != callback_data_.end());
    285   EXPECT_FALSE(callback_data_[2]);
    286   ResetCallbackData();
    287 }
    288 
    289 // Verifies that external data referenced by a policy is downloaded and cached
    290 // when first requested. Subsequent requests are served from the cache without
    291 // further download attempts.
    292 TEST_F(CloudExternalDataManagerBaseTest, DownloadAndCache) {
    293   // Serve valid external data for |k10BytePolicy|.
    294   SetFakeResponse(k10BytePolicyURL, k10ByteData, net::HTTP_OK,
    295                   net::URLRequestStatus::SUCCESS);
    296   external_data_manager_->Connect(request_content_getter_);
    297 
    298   // Retrieve external data for |k10BytePolicy|. Verify that a download happens
    299   // and the callback is invoked with the downloaded data.
    300   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0));
    301   base::RunLoop().RunUntilIdle();
    302   EXPECT_EQ(1u, callback_data_.size());
    303   ASSERT_TRUE(callback_data_[0]);
    304   EXPECT_EQ(k10ByteData, *callback_data_[0]);
    305   ResetCallbackData();
    306 
    307   // Stop serving external data for |k10BytePolicy|.
    308   fetcher_factory_.ClearFakeResponses();
    309 
    310   // Retrieve external data for |k10BytePolicy| again. Verify that no download
    311   // is attempted but the callback is still invoked with the expected data,
    312   // served from the cache.
    313   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(1));
    314   base::RunLoop().RunUntilIdle();
    315   EXPECT_EQ(1u, callback_data_.size());
    316   ASSERT_TRUE(callback_data_[1]);
    317   EXPECT_EQ(k10ByteData, *callback_data_[1]);
    318   ResetCallbackData();
    319 
    320   // Explicitly tell the external_data_manager_ to not make any download
    321   // attempts.
    322   external_data_manager_->Disconnect();
    323 
    324   // Retrieve external data for |k10BytePolicy| again. Verify that even though
    325   // downloads are not allowed, the callback is still invoked with the expected
    326   // data, served from the cache.
    327   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(2));
    328   base::RunLoop().RunUntilIdle();
    329   EXPECT_EQ(1u, callback_data_.size());
    330   ASSERT_TRUE(callback_data_[2]);
    331   EXPECT_EQ(k10ByteData, *callback_data_[2]);
    332   ResetCallbackData();
    333 
    334   // Verify that the downloaded data is present in the cache.
    335   external_data_manager_.reset();
    336   base::RunLoop().RunUntilIdle();
    337   std::string data;
    338   EXPECT_TRUE(CloudExternalDataStore(kCacheKey,
    339                                      message_loop_.message_loop_proxy(),
    340                                      resource_cache_.get()).Load(
    341       k10BytePolicy, crypto::SHA256HashString(k10ByteData), 10, &data));
    342   EXPECT_EQ(k10ByteData, data);
    343 }
    344 
    345 // Verifies that a request to download and cache all external data referenced by
    346 // policies is carried out correctly. Subsequent requests for the data are
    347 // served from the cache without further download attempts.
    348 TEST_F(CloudExternalDataManagerBaseTest, DownloadAndCacheAll) {
    349   // Serve valid external data for |k10BytePolicy| and |k20BytePolicy|.
    350   SetFakeResponse(k10BytePolicyURL, k10ByteData, net::HTTP_OK,
    351                   net::URLRequestStatus::SUCCESS);
    352   SetFakeResponse(k20BytePolicyURL, k20ByteData, net::HTTP_OK,
    353                   net::URLRequestStatus::SUCCESS);
    354   external_data_manager_->Connect(request_content_getter_);
    355 
    356   // Request that external data referenced by all policies be downloaded.
    357   FetchAll();
    358   base::RunLoop().RunUntilIdle();
    359 
    360   // Stop serving external data for |k10BytePolicy| and |k20BytePolicy|.
    361   fetcher_factory_.ClearFakeResponses();
    362 
    363   // Retrieve external data for |k10BytePolicy| and |k20BytePolicy|. Verify that
    364   // no downloads are attempted but the callbacks are still invoked with the
    365   // expected data, served from the cache.
    366   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0));
    367   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1));
    368   base::RunLoop().RunUntilIdle();
    369   EXPECT_EQ(2u, callback_data_.size());
    370   ASSERT_TRUE(callback_data_[0]);
    371   EXPECT_EQ(k10ByteData, *callback_data_[0]);
    372   ASSERT_TRUE(callback_data_[1]);
    373   EXPECT_EQ(k20ByteData, *callback_data_[1]);
    374   ResetCallbackData();
    375 
    376   // Explicitly tell the external_data_manager_ to not make any download
    377   // attempts.
    378   external_data_manager_->Disconnect();
    379 
    380   // Retrieve external data for |k10BytePolicy| and |k20BytePolicy|. Verify that
    381   // even though downloads are not allowed, the callbacks are still invoked with
    382   // the expected data, served from the cache.
    383   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(2));
    384   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(3));
    385   base::RunLoop().RunUntilIdle();
    386   EXPECT_EQ(2u, callback_data_.size());
    387   ASSERT_TRUE(callback_data_[2]);
    388   EXPECT_EQ(k10ByteData, *callback_data_[2]);
    389   ASSERT_TRUE(callback_data_[3]);
    390   EXPECT_EQ(k20ByteData, *callback_data_[3]);
    391   ResetCallbackData();
    392 
    393   // Verify that the downloaded data is present in the cache.
    394   external_data_manager_.reset();
    395   base::RunLoop().RunUntilIdle();
    396   CloudExternalDataStore cache(kCacheKey,
    397                                message_loop_.message_loop_proxy(),
    398                                resource_cache_.get());
    399   std::string data;
    400   EXPECT_TRUE(cache.Load(k10BytePolicy,
    401                          crypto::SHA256HashString(k10ByteData),
    402                          10,
    403                          &data));
    404   EXPECT_EQ(k10ByteData, data);
    405   EXPECT_TRUE(cache.Load(k20BytePolicy,
    406                          crypto::SHA256HashString(k20ByteData),
    407                          20,
    408                          &data));
    409   EXPECT_EQ(k20ByteData, data);
    410 }
    411 
    412 // Verifies that when the external data referenced by a policy is not present in
    413 // the cache and downloads are not allowed, a request to retrieve the data is
    414 // enqueued and carried out when downloads become possible.
    415 TEST_F(CloudExternalDataManagerBaseTest, DownloadAfterConnect) {
    416   // Attempt to retrieve external data for |k10BytePolicy|. Verify that the
    417   // callback is not invoked as the request remains pending.
    418   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0));
    419   base::RunLoop().RunUntilIdle();
    420   EXPECT_TRUE(callback_data_.empty());
    421   ResetCallbackData();
    422 
    423   // Serve valid external data for |k10BytePolicy| and allow the
    424   // external_data_manager_ to perform downloads.
    425   SetFakeResponse(k10BytePolicyURL, k10ByteData, net::HTTP_OK,
    426                   net::URLRequestStatus::SUCCESS);
    427   external_data_manager_->Connect(request_content_getter_);
    428 
    429   // Verify that a download happens and the callback is invoked with the
    430   // downloaded data.
    431   base::RunLoop().RunUntilIdle();
    432   EXPECT_EQ(1u, callback_data_.size());
    433   ASSERT_TRUE(callback_data_[0]);
    434   EXPECT_EQ(k10ByteData, *callback_data_[0]);
    435   ResetCallbackData();
    436 }
    437 
    438 // Verifies that when the external data referenced by a policy is not present in
    439 // the cache and cannot be downloaded at this time, a request to retrieve the
    440 // data is enqueued to be retried later.
    441 TEST_F(CloudExternalDataManagerBaseTest, DownloadError) {
    442   // Make attempts to download the external data for |k20BytePolicy| fail with
    443   // an error.
    444   SetFakeResponse(k20BytePolicyURL, std::string(),
    445                   net::HTTP_INTERNAL_SERVER_ERROR,
    446                   net::URLRequestStatus::FAILED);
    447   external_data_manager_->Connect(request_content_getter_);
    448 
    449   // Attempt to retrieve external data for |k20BytePolicy|. Verify that the
    450   // callback is not invoked as the download attempt fails and the request
    451   // remains pending.
    452   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(0));
    453   base::RunLoop().RunUntilIdle();
    454   EXPECT_TRUE(callback_data_.empty());
    455   ResetCallbackData();
    456 
    457   // Modify the external data reference for |k20BytePolicy|, allowing the
    458   // download to be retried immediately.
    459   SetExternalDataReference(
    460       k20BytePolicy,
    461       ConstructMetadata(k20BytePolicyURL,
    462                         crypto::SHA256HashString(k10ByteData)));
    463   cloud_policy_store_.NotifyStoreLoaded();
    464 
    465   // Attempt to retrieve external data for |k20BytePolicy| again. Verify that
    466   // no callback is invoked still as the download attempt fails again and the
    467   // request remains pending.
    468   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1));
    469   base::RunLoop().RunUntilIdle();
    470   EXPECT_TRUE(callback_data_.empty());
    471   ResetCallbackData();
    472 
    473   // Modify the external data reference for |k20BytePolicy|, allowing the
    474   // download to be retried immediately.
    475   SetExternalDataReference(
    476       k20BytePolicy,
    477       ConstructMetadata(k20BytePolicyURL,
    478                         crypto::SHA256HashString(k20ByteData)));
    479   cloud_policy_store_.NotifyStoreLoaded();
    480 
    481   // Serve external data for |k20BytePolicy| that does not match the hash
    482   // specified in its current external data reference.
    483   SetFakeResponse(k20BytePolicyURL, k10ByteData, net::HTTP_OK,
    484                   net::URLRequestStatus::SUCCESS);
    485 
    486   // Attempt to retrieve external data for |k20BytePolicy| again. Verify that
    487   // no callback is invoked still as the downloaded succeeds but returns data
    488   // that does not match the external data reference.
    489   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(2));
    490   base::RunLoop().RunUntilIdle();
    491   EXPECT_TRUE(callback_data_.empty());
    492   ResetCallbackData();
    493 
    494   // Modify the external data reference for |k20BytePolicy|, allowing the
    495   // download to be retried immediately. The external data reference now matches
    496   // the data being served.
    497   SetExternalDataReference(
    498       k20BytePolicy,
    499       ConstructMetadata(k20BytePolicyURL,
    500                         crypto::SHA256HashString(k10ByteData)));
    501   cloud_policy_store_.NotifyStoreLoaded();
    502 
    503   // Attempt to retrieve external data for |k20BytePolicy| again. Verify that
    504   // the current callback and the three previously enqueued callbacks are
    505   // invoked with the downloaded data now.
    506   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(3));
    507   base::RunLoop().RunUntilIdle();
    508   EXPECT_EQ(4u, callback_data_.size());
    509   ASSERT_TRUE(callback_data_[0]);
    510   EXPECT_EQ(k10ByteData, *callback_data_[0]);
    511   ASSERT_TRUE(callback_data_[1]);
    512   EXPECT_EQ(k10ByteData, *callback_data_[1]);
    513   ASSERT_TRUE(callback_data_[2]);
    514   EXPECT_EQ(k10ByteData, *callback_data_[2]);
    515   ASSERT_TRUE(callback_data_[3]);
    516   EXPECT_EQ(k10ByteData, *callback_data_[3]);
    517   ResetCallbackData();
    518 }
    519 
    520 // Verifies that when the external data referenced by a policy is present in the
    521 // cache, a request to retrieve it is served from the cache without any download
    522 // attempts.
    523 TEST_F(CloudExternalDataManagerBaseTest, LoadFromCache) {
    524   // Store valid external data for |k10BytePolicy| in the cache.
    525   external_data_manager_.reset();
    526   base::RunLoop().RunUntilIdle();
    527   EXPECT_TRUE(CloudExternalDataStore(kCacheKey,
    528                                      message_loop_.message_loop_proxy(),
    529                                      resource_cache_.get()).Store(
    530       k10BytePolicy, crypto::SHA256HashString(k10ByteData), k10ByteData));
    531 
    532   // Instantiate an external_data_manager_ that uses the primed cache.
    533   SetUpExternalDataManager();
    534   external_data_manager_->Connect(request_content_getter_);
    535 
    536   // Retrieve external data for |k10BytePolicy|. Verify that no download is
    537   // attempted but the callback is still invoked with the expected data, served
    538   // from the cache.
    539   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0));
    540   base::RunLoop().RunUntilIdle();
    541   EXPECT_EQ(1u, callback_data_.size());
    542   ASSERT_TRUE(callback_data_[0]);
    543   EXPECT_EQ(k10ByteData, *callback_data_[0]);
    544   ResetCallbackData();
    545 }
    546 
    547 // Verifies that cache entries which do not correspond to the external data
    548 // referenced by any policy are pruned on startup.
    549 TEST_F(CloudExternalDataManagerBaseTest, PruneCacheOnStartup) {
    550   external_data_manager_.reset();
    551   base::RunLoop().RunUntilIdle();
    552   scoped_ptr<CloudExternalDataStore>
    553       cache(new CloudExternalDataStore(kCacheKey,
    554                                        message_loop_.message_loop_proxy(),
    555                                        resource_cache_.get()));
    556   // Store valid external data for |k10BytePolicy| in the cache.
    557   EXPECT_TRUE(cache->Store(k10BytePolicy,
    558                            crypto::SHA256HashString(k10ByteData),
    559                            k10ByteData));
    560   // Store external data for |k20BytePolicy| that does not match the hash in its
    561   // external data reference.
    562   EXPECT_TRUE(cache->Store(k20BytePolicy,
    563                            crypto::SHA256HashString(k10ByteData),
    564                            k10ByteData));
    565   // Store external data for |kUnknownPolicy|, which is not a known policy and
    566   // therefore, cannot be referencing any external data.
    567   EXPECT_TRUE(cache->Store(kUnknownPolicy,
    568                            crypto::SHA256HashString(k10ByteData),
    569                            k10ByteData));
    570   cache.reset();
    571 
    572   // Instantiate and destroy an ExternalDataManager that uses the primed cache.
    573   SetUpExternalDataManager();
    574   external_data_manager_.reset();
    575   base::RunLoop().RunUntilIdle();
    576 
    577   cache.reset(new CloudExternalDataStore(kCacheKey,
    578                                          message_loop_.message_loop_proxy(),
    579                                          resource_cache_.get()));
    580   std::string data;
    581   // Verify that the valid external data for |k10BytePolicy| is still in the
    582   // cache.
    583   EXPECT_TRUE(cache->Load(k10BytePolicy,
    584                           crypto::SHA256HashString(k10ByteData),
    585                           10,
    586                           &data));
    587   EXPECT_EQ(k10ByteData, data);
    588   // Verify that the external data for |k20BytePolicy| and |kUnknownPolicy| has
    589   // been pruned from the cache.
    590   EXPECT_FALSE(cache->Load(k20BytePolicy,
    591                            crypto::SHA256HashString(k10ByteData),
    592                            20,
    593                            &data));
    594   EXPECT_FALSE(cache->Load(kUnknownPolicy,
    595                            crypto::SHA256HashString(k10ByteData),
    596                            20,
    597                            &data));
    598 }
    599 
    600 // Verifies that when the external data referenced by a policy is present in the
    601 // cache and the reference changes, the old data is pruned from the cache.
    602 TEST_F(CloudExternalDataManagerBaseTest, PruneCacheOnChange) {
    603   // Store valid external data for |k20BytePolicy| in the cache.
    604   external_data_manager_.reset();
    605   base::RunLoop().RunUntilIdle();
    606   scoped_ptr<CloudExternalDataStore>
    607       cache(new CloudExternalDataStore(kCacheKey,
    608                                        message_loop_.message_loop_proxy(),
    609                                        resource_cache_.get()));
    610   EXPECT_TRUE(cache->Store(k20BytePolicy,
    611                            crypto::SHA256HashString(k20ByteData),
    612                            k20ByteData));
    613   cache.reset();
    614 
    615   // Instantiate an ExternalDataManager that uses the primed cache.
    616   SetUpExternalDataManager();
    617   external_data_manager_->Connect(request_content_getter_);
    618 
    619   // Modify the external data reference for |k20BytePolicy|.
    620   SetExternalDataReference(
    621       k20BytePolicy,
    622       ConstructMetadata(k20BytePolicyURL,
    623                         crypto::SHA256HashString(k10ByteData)));
    624   cloud_policy_store_.NotifyStoreLoaded();
    625 
    626   // Verify that the old external data for |k20BytePolicy| has been pruned from
    627   // the cache.
    628   external_data_manager_.reset();
    629   base::RunLoop().RunUntilIdle();
    630   cache.reset(new CloudExternalDataStore(kCacheKey,
    631                                          message_loop_.message_loop_proxy(),
    632                                          resource_cache_.get()));
    633   std::string data;
    634   EXPECT_FALSE(cache->Load(k20BytePolicy,
    635                            crypto::SHA256HashString(k20ByteData),
    636                            20,
    637                            &data));
    638 }
    639 
    640 // Verifies that corrupt cache entries are detected and deleted when accessed.
    641 TEST_F(CloudExternalDataManagerBaseTest, CacheCorruption) {
    642   external_data_manager_.reset();
    643   base::RunLoop().RunUntilIdle();
    644   scoped_ptr<CloudExternalDataStore>
    645       cache(new CloudExternalDataStore(kCacheKey,
    646                                        message_loop_.message_loop_proxy(),
    647                                        resource_cache_.get()));
    648   // Store external data for |k10BytePolicy| that exceeds the maximal external
    649   // data size allowed for that policy.
    650   EXPECT_TRUE(cache->Store(k10BytePolicy,
    651                            crypto::SHA256HashString(k20ByteData),
    652                            k20ByteData));
    653   // Store external data for |k20BytePolicy| that is corrupted and does not
    654   // match the expected hash.
    655   EXPECT_TRUE(cache->Store(k20BytePolicy,
    656                            crypto::SHA256HashString(k20ByteData),
    657                            k10ByteData));
    658   cache.reset();
    659 
    660   SetUpExternalDataManager();
    661   // Serve external data for |k10BytePolicy| that exceeds the maximal external
    662   // data size allowed for that policy.
    663   SetFakeResponse(k10BytePolicyURL, k20ByteData, net::HTTP_OK,
    664                   net::URLRequestStatus::SUCCESS);
    665   external_data_manager_->Connect(request_content_getter_);
    666 
    667   // Modify the external data reference for |k10BytePolicy| to match the
    668   // external data being served.
    669   SetExternalDataReference(
    670       k10BytePolicy,
    671       ConstructMetadata(k10BytePolicyURL,
    672                         crypto::SHA256HashString(k20ByteData)));
    673   cloud_policy_store_.NotifyStoreLoaded();
    674 
    675   // Retrieve external data for |k10BytePolicy|. Verify that the callback is
    676   // not invoked as the cached and downloaded external data exceed the maximal
    677   // size allowed for this policy and the request remains pending.
    678   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0));
    679   base::RunLoop().RunUntilIdle();
    680   EXPECT_TRUE(callback_data_.empty());
    681   ResetCallbackData();
    682 
    683   // Serve valid external data for |k20BytePolicy|.
    684   SetFakeResponse(k20BytePolicyURL, k20ByteData, net::HTTP_OK,
    685                   net::URLRequestStatus::SUCCESS);
    686 
    687   // Retrieve external data for |k20BytePolicy|. Verify that the callback is
    688   // invoked with the valid downloaded data, not the invalid data in the cache.
    689   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1));
    690   base::RunLoop().RunUntilIdle();
    691   EXPECT_EQ(1u, callback_data_.size());
    692   ASSERT_TRUE(callback_data_[1]);
    693   EXPECT_EQ(k20ByteData, *callback_data_[1]);
    694   ResetCallbackData();
    695 
    696   external_data_manager_.reset();
    697   base::RunLoop().RunUntilIdle();
    698   cache.reset(new CloudExternalDataStore(kCacheKey,
    699                                          message_loop_.message_loop_proxy(),
    700                                          resource_cache_.get()));
    701   std::string data;
    702   // Verify that the invalid external data for |k10BytePolicy| has been pruned
    703   // from the cache. Load() will return |false| in two cases:
    704   // 1) The cache entry for |k10BytePolicy| has been pruned.
    705   // 2) The cache entry for |k10BytePolicy| still exists but the cached data
    706   //    does not match the expected hash or exceeds the maximum size allowed.
    707   // To test for the former, Load() is called with a maximum data size and hash
    708   // that would allow the data originally written to the cache to be loaded.
    709   // When this fails, it is certain that the original data is no longer present
    710   // in the cache.
    711   EXPECT_FALSE(cache->Load(k10BytePolicy,
    712                            crypto::SHA256HashString(k20ByteData),
    713                            20,
    714                            &data));
    715   // Verify that the invalid external data for |k20BytePolicy| has been replaced
    716   // with the downloaded valid data in the cache.
    717   EXPECT_TRUE(cache->Load(k20BytePolicy,
    718                           crypto::SHA256HashString(k20ByteData),
    719                           20,
    720                           &data));
    721   EXPECT_EQ(k20ByteData, data);
    722 }
    723 
    724 // Verifies that when the external data reference for a policy changes while a
    725 // download of the external data for that policy is pending, the download is
    726 // immediately retried using the new reference.
    727 TEST_F(CloudExternalDataManagerBaseTest, PolicyChangeWhileDownloadPending) {
    728   // Make attempts to download the external data for |k10BytePolicy| and
    729   // |k20BytePolicy| fail with an error.
    730   SetFakeResponse(k10BytePolicyURL, std::string(),
    731                   net::HTTP_INTERNAL_SERVER_ERROR,
    732                   net::URLRequestStatus::FAILED);
    733   SetFakeResponse(k20BytePolicyURL, std::string(),
    734                   net::HTTP_INTERNAL_SERVER_ERROR,
    735                   net::URLRequestStatus::FAILED);
    736   external_data_manager_->Connect(request_content_getter_);
    737 
    738   // Attempt to retrieve external data for |k10BytePolicy| and |k20BytePolicy|.
    739   // Verify that no callbacks are invoked as the download attempts fail and the
    740   // requests remain pending.
    741   external_data_manager_->Fetch(k10BytePolicy, ConstructFetchCallback(0));
    742   external_data_manager_->Fetch(k20BytePolicy, ConstructFetchCallback(1));
    743   base::RunLoop().RunUntilIdle();
    744   EXPECT_TRUE(callback_data_.empty());
    745   ResetCallbackData();
    746 
    747   // Modify the external data reference for |k10BytePolicy| to be invalid.
    748   // Verify that the callback is invoked as the policy no longer has a valid
    749   // external data reference.
    750   cloud_policy_store_.policy_map_.Erase(k10BytePolicy);
    751   cloud_policy_store_.NotifyStoreLoaded();
    752   base::RunLoop().RunUntilIdle();
    753   EXPECT_EQ(1u, callback_data_.size());
    754   EXPECT_TRUE(callback_data_.find(0) != callback_data_.end());
    755   EXPECT_FALSE(callback_data_[0]);
    756   ResetCallbackData();
    757 
    758   // Serve valid external data for |k20BytePolicy|.
    759   fetcher_factory_.ClearFakeResponses();
    760   SetFakeResponse(k20BytePolicyURL, k10ByteData, net::HTTP_OK,
    761                   net::URLRequestStatus::SUCCESS);
    762 
    763   // Modify the external data reference for |k20BytePolicy| to match the
    764   // external data now being served. Verify that the callback is invoked with
    765   // the downloaded data.
    766   SetExternalDataReference(
    767       k20BytePolicy,
    768       ConstructMetadata(k20BytePolicyURL,
    769                         crypto::SHA256HashString(k10ByteData)));
    770   cloud_policy_store_.NotifyStoreLoaded();
    771   base::RunLoop().RunUntilIdle();
    772   EXPECT_EQ(1u, callback_data_.size());
    773   ASSERT_TRUE(callback_data_[1]);
    774   EXPECT_EQ(k10ByteData, *callback_data_[1]);
    775   ResetCallbackData();
    776 }
    777 
    778 }  // namespace policy
    779