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