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