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_store.h"
6
7#include "base/compiler_specific.h"
8#include "base/files/scoped_temp_dir.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/test/test_simple_task_runner.h"
11#include "components/policy/core/common/cloud/resource_cache.h"
12#include "crypto/sha2.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace policy {
16
17namespace {
18
19const char kKey1[] = "Key 1";
20const char kKey2[] = "Key 2";
21const char kPolicy1[] = "Test policy 1";
22const char kPolicy2[] = "Test policy 2";
23const char kData1[] = "Testing data 1";
24const char kData2[] = "Testing data 2";
25const char kURL[] = "http://localhost";
26const size_t kMaxSize = 100;
27
28}  // namespace
29
30class CouldExternalDataStoreTest : public testing::Test {
31 public:
32  CouldExternalDataStoreTest();
33
34  virtual void SetUp() OVERRIDE;
35
36 protected:
37  const std::string kData1Hash;
38  const std::string kData2Hash;
39
40  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
41  base::ScopedTempDir temp_dir_;
42  scoped_ptr<ResourceCache> resource_cache_;
43
44  DISALLOW_COPY_AND_ASSIGN(CouldExternalDataStoreTest);
45};
46
47CouldExternalDataStoreTest::CouldExternalDataStoreTest()
48    : kData1Hash(crypto::SHA256HashString(kData1)),
49      kData2Hash(crypto::SHA256HashString(kData2)),
50      task_runner_(new base::TestSimpleTaskRunner) {
51}
52
53void CouldExternalDataStoreTest::SetUp() {
54  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
55  resource_cache_.reset(new ResourceCache(temp_dir_.path(), task_runner_));
56}
57
58TEST_F(CouldExternalDataStoreTest, StoreAndLoad) {
59  // Write an entry to a store.
60  CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
61  EXPECT_TRUE(store.Store(kPolicy1, kData1Hash, kData1));
62
63  // Check that loading and verifying the entry against an invalid hash fails.
64  std::string data;
65  EXPECT_FALSE(store.Load(kPolicy1, kData2Hash, kMaxSize, &data));
66
67  // Check that loading and verifying the entry against its hash succeeds.
68  EXPECT_TRUE(store.Load(kPolicy1, kData1Hash, kMaxSize, &data));
69  EXPECT_EQ(kData1, data);
70}
71
72TEST_F(CouldExternalDataStoreTest, StoreTooLargeAndLoad) {
73  // Write an entry to a store.
74  CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
75  EXPECT_TRUE(store.Store(kPolicy1, kData1Hash, kData2));
76
77  // Check that the entry has been written to the resource cache backing the
78  // store.
79  std::map<std::string, std::string> contents;
80  resource_cache_->LoadAllSubkeys(kKey1, &contents);
81  ASSERT_EQ(1u, contents.size());
82  EXPECT_EQ(kData2, contents.begin()->second);
83
84  // Check that loading the entry fails when the maximum allowed data size is
85  // smaller than the entry size.
86  std::string data;
87  EXPECT_FALSE(store.Load(kPolicy1, kData1Hash, 1, &data));
88
89  // Verify that the oversized entry has been detected and removed from the
90  // resource cache.
91  resource_cache_->LoadAllSubkeys(kKey1, &contents);
92  EXPECT_TRUE(contents.empty());
93}
94
95TEST_F(CouldExternalDataStoreTest, StoreInvalidAndLoad) {
96  // Construct a store entry whose hash and contents do not match.
97  CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
98  EXPECT_TRUE(store.Store(kPolicy1, kData1Hash, kData2));
99
100  // Check that the entry has been written to the resource cache backing the
101  // store.
102  std::map<std::string, std::string> contents;
103  resource_cache_->LoadAllSubkeys(kKey1, &contents);
104  ASSERT_EQ(1u, contents.size());
105  EXPECT_EQ(kData2, contents.begin()->second);
106
107  // Check that loading and verifying the entry against its hash fails.
108  std::string data;
109  EXPECT_FALSE(store.Load(kPolicy1, kData1Hash, kMaxSize, &data));
110
111  // Verify that the corrupted entry has been detected and removed from the
112  // resource cache.
113  resource_cache_->LoadAllSubkeys(kKey1, &contents);
114  EXPECT_TRUE(contents.empty());
115}
116
117TEST_F(CouldExternalDataStoreTest, Prune) {
118  // Write two entries to a store.
119  CloudExternalDataStore store(kKey1, task_runner_, resource_cache_.get());
120  EXPECT_TRUE(store.Store(kPolicy1, kData1Hash, kData1));
121  EXPECT_TRUE(store.Store(kPolicy2, kData2Hash, kData2));
122
123  // Check that loading and verifying the entries against their hashes succeeds.
124  std::string data;
125  EXPECT_TRUE(store.Load(kPolicy1, kData1Hash, kMaxSize, &data));
126  EXPECT_EQ(kData1, data);
127  EXPECT_TRUE(store.Load(kPolicy2, kData2Hash, kMaxSize, &data));
128  EXPECT_EQ(kData2, data);
129
130  // Prune the store, allowing only an entry for the first policy with its
131  // current hash to be kept.
132  CloudExternalDataManager::Metadata metadata;
133  metadata[kPolicy1] =
134      CloudExternalDataManager::MetadataEntry(kURL, kData1Hash);
135  store.Prune(metadata);
136
137  // Check that the entry for the second policy has been removed from the
138  // resource cache backing the store.
139  std::map<std::string, std::string> contents;
140  resource_cache_->LoadAllSubkeys(kKey1, &contents);
141  ASSERT_EQ(1u, contents.size());
142  EXPECT_EQ(kData1, contents.begin()->second);
143
144  // Prune the store, allowing only an entry for the first policy with a
145  // different hash to be kept.
146  metadata[kPolicy1] =
147      CloudExternalDataManager::MetadataEntry(kURL, kData2Hash);
148  store.Prune(metadata);
149
150  // Check that the entry for the first policy has been removed from the
151  // resource cache.
152  resource_cache_->LoadAllSubkeys(kKey1, &contents);
153  EXPECT_TRUE(contents.empty());
154}
155
156TEST_F(CouldExternalDataStoreTest, SharedCache) {
157  // Write entries to two stores for two different cache_keys sharing a cache.
158  CloudExternalDataStore store1(kKey1, task_runner_, resource_cache_.get());
159  EXPECT_TRUE(store1.Store(kPolicy1, kData1Hash, kData1));
160  CloudExternalDataStore store2(kKey2, task_runner_, resource_cache_.get());
161  EXPECT_TRUE(store2.Store(kPolicy2, kData2Hash, kData2));
162
163  // Check that the entries have been assigned to the correct keys in the
164  // resource cache backing the stores.
165  std::map<std::string, std::string> contents;
166  resource_cache_->LoadAllSubkeys(kKey1, &contents);
167  ASSERT_EQ(1u, contents.size());
168  EXPECT_EQ(kData1, contents.begin()->second);
169  resource_cache_->LoadAllSubkeys(kKey2, &contents);
170  ASSERT_EQ(1u, contents.size());
171  EXPECT_EQ(kData2, contents.begin()->second);
172
173  // Check that each entry can be loaded from the correct store.
174  std::string data;
175  EXPECT_TRUE(store1.Load(kPolicy1, kData1Hash, kMaxSize, &data));
176  EXPECT_EQ(kData1, data);
177  EXPECT_FALSE(store1.Load(kPolicy2, kData2Hash, kMaxSize, &data));
178
179  EXPECT_FALSE(store2.Load(kPolicy1, kData1Hash, kMaxSize, &data));
180  EXPECT_TRUE(store2.Load(kPolicy2, kData2Hash, kMaxSize, &data));
181  EXPECT_EQ(kData2, data);
182
183  // Prune the first store, allowing no entries to be kept.
184  CloudExternalDataManager::Metadata metadata;
185  store1.Prune(metadata);
186
187  // Check that the part of the resource cache backing the first store is empty.
188  resource_cache_->LoadAllSubkeys(kKey1, &contents);
189  EXPECT_TRUE(contents.empty());
190
191  // Check that the part of the resource cache backing the second store is
192  // unaffected.
193  resource_cache_->LoadAllSubkeys(kKey2, &contents);
194  ASSERT_EQ(1u, contents.size());
195  EXPECT_EQ(kData2, contents.begin()->second);
196}
197
198}  // namespace policy
199