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 "components/policy/core/common/async_policy_provider.h"
6
7#include "base/callback.h"
8#include "base/memory/ref_counted.h"
9#include "base/message_loop/message_loop.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "base/sequenced_task_runner.h"
12#include "base/values.h"
13#include "components/policy/core/common/async_policy_loader.h"
14#include "components/policy/core/common/external_data_fetcher.h"
15#include "components/policy/core/common/mock_configuration_policy_provider.h"
16#include "components/policy/core/common/schema_registry.h"
17#include "testing/gmock/include/gmock/gmock.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20using testing::Mock;
21using testing::Return;
22using testing::Sequence;
23
24namespace policy {
25
26namespace {
27
28// Helper to write a policy in |bundle| with less code.
29void SetPolicy(PolicyBundle* bundle,
30               const std::string& name,
31               const std::string& value) {
32  bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
33      .Set(name,
34           POLICY_LEVEL_MANDATORY,
35           POLICY_SCOPE_USER,
36           new base::StringValue(value),
37           NULL);
38}
39
40class MockPolicyLoader : public AsyncPolicyLoader {
41 public:
42  explicit MockPolicyLoader(
43      scoped_refptr<base::SequencedTaskRunner> task_runner);
44  virtual ~MockPolicyLoader();
45
46  // Load() returns a scoped_ptr<PolicyBundle> but it can't be mocked because
47  // scoped_ptr is moveable but not copyable. This override forwards the
48  // call to MockLoad() which returns a PolicyBundle*, and returns a copy
49  // wrapped in a passed scoped_ptr.
50  virtual scoped_ptr<PolicyBundle> Load() OVERRIDE;
51
52  MOCK_METHOD0(MockLoad, const PolicyBundle*());
53  MOCK_METHOD0(InitOnBackgroundThread, void());
54  MOCK_METHOD0(LastModificationTime, base::Time());
55
56 private:
57  DISALLOW_COPY_AND_ASSIGN(MockPolicyLoader);
58};
59
60MockPolicyLoader::MockPolicyLoader(
61    scoped_refptr<base::SequencedTaskRunner> task_runner)
62    : AsyncPolicyLoader(task_runner) {}
63
64MockPolicyLoader::~MockPolicyLoader() {}
65
66scoped_ptr<PolicyBundle> MockPolicyLoader::Load() {
67  scoped_ptr<PolicyBundle> bundle;
68  const PolicyBundle* loaded = MockLoad();
69  if (loaded) {
70    bundle.reset(new PolicyBundle());
71    bundle->CopyFrom(*loaded);
72  }
73  return bundle.Pass();
74}
75
76}  // namespace
77
78class AsyncPolicyProviderTest : public testing::Test {
79 protected:
80  AsyncPolicyProviderTest();
81  virtual ~AsyncPolicyProviderTest();
82
83  virtual void SetUp() OVERRIDE;
84  virtual void TearDown() OVERRIDE;
85
86  base::MessageLoop loop_;
87  SchemaRegistry schema_registry_;
88  PolicyBundle initial_bundle_;
89  MockPolicyLoader* loader_;
90  scoped_ptr<AsyncPolicyProvider> provider_;
91
92 private:
93  DISALLOW_COPY_AND_ASSIGN(AsyncPolicyProviderTest);
94};
95
96AsyncPolicyProviderTest::AsyncPolicyProviderTest() {}
97
98AsyncPolicyProviderTest::~AsyncPolicyProviderTest() {}
99
100void AsyncPolicyProviderTest::SetUp() {
101  SetPolicy(&initial_bundle_, "policy", "initial");
102  loader_ = new MockPolicyLoader(loop_.message_loop_proxy());
103  EXPECT_CALL(*loader_, LastModificationTime())
104      .WillRepeatedly(Return(base::Time()));
105  EXPECT_CALL(*loader_, InitOnBackgroundThread()).Times(1);
106  EXPECT_CALL(*loader_, MockLoad()).WillOnce(Return(&initial_bundle_));
107
108  provider_.reset(new AsyncPolicyProvider(
109      &schema_registry_, scoped_ptr<AsyncPolicyLoader>(loader_)));
110  provider_->Init(&schema_registry_);
111  // Verify that the initial load is done synchronously:
112  EXPECT_TRUE(provider_->policies().Equals(initial_bundle_));
113
114  loop_.RunUntilIdle();
115  Mock::VerifyAndClearExpectations(loader_);
116
117  EXPECT_CALL(*loader_, LastModificationTime())
118      .WillRepeatedly(Return(base::Time()));
119}
120
121void AsyncPolicyProviderTest::TearDown() {
122  if (provider_) {
123    provider_->Shutdown();
124    provider_.reset();
125  }
126  loop_.RunUntilIdle();
127}
128
129TEST_F(AsyncPolicyProviderTest, RefreshPolicies) {
130  PolicyBundle refreshed_bundle;
131  SetPolicy(&refreshed_bundle, "policy", "refreshed");
132  EXPECT_CALL(*loader_, MockLoad()).WillOnce(Return(&refreshed_bundle));
133
134  MockConfigurationPolicyObserver observer;
135  provider_->AddObserver(&observer);
136  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
137  provider_->RefreshPolicies();
138  loop_.RunUntilIdle();
139  // The refreshed policies are now provided.
140  EXPECT_TRUE(provider_->policies().Equals(refreshed_bundle));
141  provider_->RemoveObserver(&observer);
142}
143
144TEST_F(AsyncPolicyProviderTest, RefreshPoliciesTwice) {
145  PolicyBundle refreshed_bundle;
146  SetPolicy(&refreshed_bundle, "policy", "refreshed");
147  EXPECT_CALL(*loader_, MockLoad()).WillRepeatedly(Return(&refreshed_bundle));
148
149  MockConfigurationPolicyObserver observer;
150  provider_->AddObserver(&observer);
151  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
152  provider_->RefreshPolicies();
153  // Doesn't refresh before going through the background thread.
154  Mock::VerifyAndClearExpectations(&observer);
155
156  // Doesn't refresh if another RefreshPolicies request is made.
157  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
158  provider_->RefreshPolicies();
159  Mock::VerifyAndClearExpectations(&observer);
160
161  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
162  loop_.RunUntilIdle();
163  // The refreshed policies are now provided.
164  EXPECT_TRUE(provider_->policies().Equals(refreshed_bundle));
165  Mock::VerifyAndClearExpectations(&observer);
166  provider_->RemoveObserver(&observer);
167}
168
169TEST_F(AsyncPolicyProviderTest, RefreshPoliciesDuringReload) {
170  PolicyBundle reloaded_bundle;
171  SetPolicy(&reloaded_bundle, "policy", "reloaded");
172  PolicyBundle refreshed_bundle;
173  SetPolicy(&refreshed_bundle, "policy", "refreshed");
174
175  Sequence load_sequence;
176  // Reload.
177  EXPECT_CALL(*loader_, MockLoad()).InSequence(load_sequence)
178                                   .WillOnce(Return(&reloaded_bundle));
179  // RefreshPolicies.
180  EXPECT_CALL(*loader_, MockLoad()).InSequence(load_sequence)
181                                   .WillOnce(Return(&refreshed_bundle));
182
183  MockConfigurationPolicyObserver observer;
184  provider_->AddObserver(&observer);
185  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
186
187  // A Reload is triggered before RefreshPolicies, and it shouldn't trigger
188  // notifications.
189  loader_->Reload(true);
190  Mock::VerifyAndClearExpectations(&observer);
191
192  // Doesn't refresh before going through the background thread.
193  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
194  provider_->RefreshPolicies();
195  Mock::VerifyAndClearExpectations(&observer);
196
197  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(1);
198  loop_.RunUntilIdle();
199  // The refreshed policies are now provided, and the |reloaded_bundle| was
200  // dropped.
201  EXPECT_TRUE(provider_->policies().Equals(refreshed_bundle));
202  Mock::VerifyAndClearExpectations(&observer);
203  provider_->RemoveObserver(&observer);
204}
205
206TEST_F(AsyncPolicyProviderTest, Shutdown) {
207  EXPECT_CALL(*loader_, MockLoad()).WillRepeatedly(Return(&initial_bundle_));
208
209  MockConfigurationPolicyObserver observer;
210  provider_->AddObserver(&observer);
211
212  // Though there is a pending Reload, the provider and the loader can be
213  // deleted at any time.
214  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
215  loader_->Reload(true);
216  Mock::VerifyAndClearExpectations(&observer);
217
218  EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
219  provider_->Shutdown();
220  loop_.RunUntilIdle();
221  Mock::VerifyAndClearExpectations(&observer);
222
223  provider_->RemoveObserver(&observer);
224  provider_.reset();
225}
226
227}  // namespace policy
228