1// Copyright (c) 2012 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/cloud/cloud_policy_service.h" 6 7#include "base/bind.h" 8#include "base/callback.h" 9#include "components/policy/core/common/cloud/cloud_policy_constants.h" 10#include "components/policy/core/common/cloud/mock_cloud_policy_client.h" 11#include "components/policy/core/common/cloud/mock_cloud_policy_store.h" 12#include "policy/proto/device_management_backend.pb.h" 13#include "testing/gmock/include/gmock/gmock.h" 14#include "testing/gtest/include/gtest/gtest.h" 15 16namespace em = enterprise_management; 17 18using testing::_; 19 20namespace policy { 21 22class MockCloudPolicyServiceObserver : public CloudPolicyService::Observer { 23 public: 24 MockCloudPolicyServiceObserver() {} 25 virtual ~MockCloudPolicyServiceObserver() {} 26 27 MOCK_METHOD1(OnInitializationCompleted, void(CloudPolicyService* service)); 28 private: 29 DISALLOW_COPY_AND_ASSIGN(MockCloudPolicyServiceObserver); 30}; 31 32class CloudPolicyServiceTest : public testing::Test { 33 public: 34 CloudPolicyServiceTest() 35 : policy_ns_key_(dm_protocol::kChromeUserPolicyType, std::string()), 36 service_(policy_ns_key_, &client_, &store_) {} 37 38 MOCK_METHOD1(OnPolicyRefresh, void(bool)); 39 40 protected: 41 PolicyNamespaceKey policy_ns_key_; 42 MockCloudPolicyClient client_; 43 MockCloudPolicyStore store_; 44 CloudPolicyService service_; 45}; 46 47MATCHER_P(ProtoMatches, proto, "") { 48 return arg.SerializePartialAsString() == proto.SerializePartialAsString(); 49} 50 51TEST_F(CloudPolicyServiceTest, ManagedByEmptyPolicy) { 52 EXPECT_EQ("", service_.ManagedBy()); 53} 54 55TEST_F(CloudPolicyServiceTest, ManagedByValidPolicy) { 56 store_.policy_.reset(new em::PolicyData()); 57 store_.policy_->set_username("user@example.com"); 58 EXPECT_EQ("example.com", service_.ManagedBy()); 59} 60 61TEST_F(CloudPolicyServiceTest, PolicyUpdateSuccess) { 62 em::PolicyFetchResponse policy; 63 policy.set_policy_data("fake policy"); 64 client_.SetPolicy(policy_ns_key_, policy); 65 EXPECT_CALL(store_, Store(ProtoMatches(policy))).Times(1); 66 client_.NotifyPolicyFetched(); 67 68 // After |store_| initializes, credentials and other meta data should be 69 // transferred to |client_|. 70 store_.policy_.reset(new em::PolicyData()); 71 store_.policy_->set_request_token("fake token"); 72 store_.policy_->set_device_id("fake client id"); 73 store_.policy_->set_timestamp(32); 74 store_.policy_->set_valid_serial_number_missing(true); 75 store_.policy_->set_public_key_version(17); 76 EXPECT_CALL(client_, 77 SetupRegistration(store_.policy_->request_token(), 78 store_.policy_->device_id())).Times(1); 79 store_.NotifyStoreLoaded(); 80 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMilliseconds(32), 81 client_.last_policy_timestamp_); 82 EXPECT_TRUE(client_.submit_machine_id_); 83 EXPECT_TRUE(client_.public_key_version_valid_); 84 EXPECT_EQ(17, client_.public_key_version_); 85} 86 87TEST_F(CloudPolicyServiceTest, PolicyUpdateClientFailure) { 88 client_.SetStatus(DM_STATUS_REQUEST_FAILED); 89 EXPECT_CALL(store_, Store(_)).Times(0); 90 client_.NotifyPolicyFetched(); 91} 92 93TEST_F(CloudPolicyServiceTest, RefreshPolicySuccess) { 94 testing::InSequence seq; 95 96 EXPECT_CALL(*this, OnPolicyRefresh(_)).Times(0); 97 client_.SetDMToken("fake token"); 98 99 // Trigger a fetch on the client. 100 EXPECT_CALL(client_, FetchPolicy()).Times(1); 101 service_.RefreshPolicy(base::Bind(&CloudPolicyServiceTest::OnPolicyRefresh, 102 base::Unretained(this))); 103 104 // Client responds, push policy to store. 105 em::PolicyFetchResponse policy; 106 policy.set_policy_data("fake policy"); 107 client_.SetPolicy(policy_ns_key_, policy); 108 client_.fetched_invalidation_version_ = 12345; 109 EXPECT_CALL(store_, Store(ProtoMatches(policy))).Times(1); 110 EXPECT_EQ(0, store_.invalidation_version()); 111 client_.NotifyPolicyFetched(); 112 EXPECT_EQ(12345, store_.invalidation_version()); 113 114 // Store reloads policy, callback gets triggered. 115 store_.policy_.reset(new em::PolicyData()); 116 store_.policy_->set_request_token("token"); 117 store_.policy_->set_device_id("device-id"); 118 EXPECT_CALL(*this, OnPolicyRefresh(true)).Times(1); 119 store_.NotifyStoreLoaded(); 120} 121 122TEST_F(CloudPolicyServiceTest, RefreshPolicyNotRegistered) { 123 // Clear the token so the client is not registered. 124 client_.SetDMToken(std::string()); 125 126 EXPECT_CALL(client_, FetchPolicy()).Times(0); 127 EXPECT_CALL(*this, OnPolicyRefresh(false)).Times(1); 128 service_.RefreshPolicy(base::Bind(&CloudPolicyServiceTest::OnPolicyRefresh, 129 base::Unretained(this))); 130} 131 132TEST_F(CloudPolicyServiceTest, RefreshPolicyClientError) { 133 testing::InSequence seq; 134 135 EXPECT_CALL(*this, OnPolicyRefresh(_)).Times(0); 136 client_.SetDMToken("fake token"); 137 138 // Trigger a fetch on the client. 139 EXPECT_CALL(client_, FetchPolicy()).Times(1); 140 service_.RefreshPolicy(base::Bind(&CloudPolicyServiceTest::OnPolicyRefresh, 141 base::Unretained(this))); 142 143 // Client responds with an error, which should trigger the callback. 144 client_.SetStatus(DM_STATUS_REQUEST_FAILED); 145 EXPECT_CALL(*this, OnPolicyRefresh(false)).Times(1); 146 client_.NotifyClientError(); 147} 148 149TEST_F(CloudPolicyServiceTest, RefreshPolicyStoreError) { 150 testing::InSequence seq; 151 152 EXPECT_CALL(*this, OnPolicyRefresh(_)).Times(0); 153 client_.SetDMToken("fake token"); 154 155 // Trigger a fetch on the client. 156 EXPECT_CALL(client_, FetchPolicy()).Times(1); 157 service_.RefreshPolicy(base::Bind(&CloudPolicyServiceTest::OnPolicyRefresh, 158 base::Unretained(this))); 159 160 // Client responds, push policy to store. 161 em::PolicyFetchResponse policy; 162 policy.set_policy_data("fake policy"); 163 client_.SetPolicy(policy_ns_key_, policy); 164 EXPECT_CALL(store_, Store(ProtoMatches(policy))).Times(1); 165 client_.NotifyPolicyFetched(); 166 167 // Store fails, which should trigger the callback. 168 EXPECT_CALL(*this, OnPolicyRefresh(false)).Times(1); 169 store_.NotifyStoreError(); 170} 171 172TEST_F(CloudPolicyServiceTest, RefreshPolicyConcurrent) { 173 testing::InSequence seq; 174 175 EXPECT_CALL(*this, OnPolicyRefresh(_)).Times(0); 176 client_.SetDMToken("fake token"); 177 178 // Trigger a fetch on the client. 179 EXPECT_CALL(client_, FetchPolicy()).Times(1); 180 service_.RefreshPolicy(base::Bind(&CloudPolicyServiceTest::OnPolicyRefresh, 181 base::Unretained(this))); 182 183 // Triggering another policy refresh should generate a new fetch request. 184 EXPECT_CALL(client_, FetchPolicy()).Times(1); 185 service_.RefreshPolicy(base::Bind(&CloudPolicyServiceTest::OnPolicyRefresh, 186 base::Unretained(this))); 187 188 // Client responds, push policy to store. 189 em::PolicyFetchResponse policy; 190 policy.set_policy_data("fake policy"); 191 client_.SetPolicy(policy_ns_key_, policy); 192 EXPECT_CALL(store_, Store(ProtoMatches(policy))).Times(1); 193 client_.NotifyPolicyFetched(); 194 195 // Trigger another policy fetch. 196 EXPECT_CALL(client_, FetchPolicy()).Times(1); 197 service_.RefreshPolicy(base::Bind(&CloudPolicyServiceTest::OnPolicyRefresh, 198 base::Unretained(this))); 199 200 // The store finishing the first load should not generate callbacks. 201 EXPECT_CALL(*this, OnPolicyRefresh(_)).Times(0); 202 store_.NotifyStoreLoaded(); 203 204 // Second policy fetch finishes. 205 EXPECT_CALL(store_, Store(ProtoMatches(policy))).Times(1); 206 client_.NotifyPolicyFetched(); 207 208 // Corresponding store operation finishes, all _three_ callbacks fire. 209 EXPECT_CALL(*this, OnPolicyRefresh(true)).Times(3); 210 store_.NotifyStoreLoaded(); 211} 212 213TEST_F(CloudPolicyServiceTest, StoreAlreadyInitialized) { 214 // Service should start off initialized if the store has already loaded 215 // policy. 216 store_.NotifyStoreLoaded(); 217 CloudPolicyService service(policy_ns_key_, &client_, &store_); 218 EXPECT_TRUE(service.IsInitializationComplete()); 219} 220 221TEST_F(CloudPolicyServiceTest, StoreLoadAfterCreation) { 222 // Service should start off un-initialized if the store has not yet loaded 223 // policy. 224 EXPECT_FALSE(service_.IsInitializationComplete()); 225 MockCloudPolicyServiceObserver observer; 226 service_.AddObserver(&observer); 227 // Service should be marked as initialized and observer should be called back. 228 EXPECT_CALL(observer, OnInitializationCompleted(&service_)).Times(1); 229 store_.NotifyStoreLoaded(); 230 EXPECT_TRUE(service_.IsInitializationComplete()); 231 testing::Mock::VerifyAndClearExpectations(&observer); 232 233 // Now, the next time the store is loaded, the observer should not be called 234 // again. 235 EXPECT_CALL(observer, OnInitializationCompleted(&service_)).Times(0); 236 store_.NotifyStoreLoaded(); 237 service_.RemoveObserver(&observer); 238} 239 240} // namespace policy 241