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 37namespace policy { 38 39namespace { 40 41// A string policy. 42const char kStringPolicy[] = "StringPolicy"; 43// A policy that may reference up to 10 bytes of external data. 44const char k10BytePolicy[] = "10BytePolicy"; 45// A policy that may reference up to 20 bytes of external data. 46const char k20BytePolicy[] = "20BytePolicy"; 47// A nonexistent policy. 48const char kUnknownPolicy[] = "UnknownPolicy"; 49 50const char k10BytePolicyURL[] = "http://localhost/10_bytes"; 51const char k20BytePolicyURL[] = "http://localhost/20_bytes"; 52 53const char k10ByteData[] = "10 bytes.."; 54const char k20ByteData[] = "20 bytes............"; 55 56const 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 63const char kCacheKey[] = "data"; 64 65// A variant of net::FakeURLFetcherFactory that makes it an error to request a 66// fetcher for an unknown URL. 67class 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 83FakeURLFetcherFactory::FakeURLFetcherFactory() 84 : net::FakeURLFetcherFactory(NULL) { 85} 86 87FakeURLFetcherFactory::~FakeURLFetcherFactory() { 88} 89 90net::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 103class 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 144CloudExternalDataManagerBaseTest::CloudExternalDataManagerBaseTest() { 145} 146 147void 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 179void CloudExternalDataManagerBaseTest::TearDown() { 180 external_data_manager_.reset(); 181 base::RunLoop().RunUntilIdle(); 182 ResetCallbackData(); 183} 184 185void 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 197scoped_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 208void 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 220ExternalDataFetcher::FetchCallback 221CloudExternalDataManagerBaseTest::ConstructFetchCallback(int id) { 222 return base::Bind(&CloudExternalDataManagerBaseTest::OnFetchDone, 223 base::Unretained(this), 224 id); 225} 226 227void CloudExternalDataManagerBaseTest::ResetCallbackData() { 228 STLDeleteValues(&callback_data_); 229} 230 231void CloudExternalDataManagerBaseTest::OnFetchDone( 232 int id, 233 scoped_ptr<std::string> data) { 234 delete callback_data_[id]; 235 callback_data_[id] = data.release(); 236} 237 238void CloudExternalDataManagerBaseTest::FetchAll() { 239 external_data_manager_->FetchAll(); 240} 241 242void 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. 253TEST_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. 292TEST_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. 348TEST_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. 415TEST_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. 441TEST_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. 523TEST_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. 549TEST_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. 602TEST_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. 641TEST_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. 727TEST_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