OLD | NEW |
| (Empty) |
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 "chrome/browser/policy/cloud_policy_client.h" | |
6 | |
7 #include <map> | |
8 #include <set> | |
9 | |
10 #include "base/compiler_specific.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "chrome/browser/policy/mock_cloud_policy_client.h" | |
13 #include "chrome/browser/policy/mock_device_management_service.h" | |
14 #include "chrome/browser/policy/proto/device_management_backend.pb.h" | |
15 #include "testing/gmock/include/gmock/gmock.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 using testing::Mock; | |
19 using testing::Return; | |
20 using testing::SaveArg; | |
21 using testing::StrictMock; | |
22 using testing::_; | |
23 | |
24 namespace em = enterprise_management; | |
25 | |
26 namespace policy { | |
27 | |
28 namespace { | |
29 | |
30 const char kClientID[] = "fake-client-id"; | |
31 const char kMachineID[] = "fake-machine-id"; | |
32 const char kMachineModel[] = "fake-machine-model"; | |
33 const char kOAuthToken[] = "fake-oauth-token"; | |
34 const char kDMToken[] = "fake-dm-token"; | |
35 | |
36 class MockStatusProvider : public CloudPolicyClient::StatusProvider { | |
37 public: | |
38 MockStatusProvider() {} | |
39 virtual ~MockStatusProvider() {} | |
40 | |
41 MOCK_METHOD1(GetDeviceStatus, bool(em::DeviceStatusReportRequest* status)); | |
42 MOCK_METHOD1(GetSessionStatus, bool(em::SessionStatusReportRequest* status)); | |
43 MOCK_METHOD0(OnSubmittedSuccessfully, void(void)); | |
44 | |
45 private: | |
46 DISALLOW_COPY_AND_ASSIGN(MockStatusProvider); | |
47 }; | |
48 | |
49 MATCHER_P(MatchProto, expected, "matches protobuf") { | |
50 return arg.SerializePartialAsString() == expected.SerializePartialAsString(); | |
51 } | |
52 | |
53 } // namespace | |
54 | |
55 class CloudPolicyClientTest : public testing::Test { | |
56 protected: | |
57 CloudPolicyClientTest() | |
58 : client_id_(kClientID), | |
59 policy_ns_key_(dm_protocol::kChromeUserPolicyType, std::string()) { | |
60 em::DeviceRegisterRequest* register_request = | |
61 registration_request_.mutable_register_request(); | |
62 register_request->set_type(em::DeviceRegisterRequest::USER); | |
63 register_request->set_machine_id(kMachineID); | |
64 register_request->set_machine_model(kMachineModel); | |
65 registration_response_.mutable_register_response()-> | |
66 set_device_management_token(kDMToken); | |
67 | |
68 em::PolicyFetchRequest* policy_fetch_request = | |
69 policy_request_.mutable_policy_request()->add_request(); | |
70 policy_fetch_request->set_policy_type(dm_protocol::kChromeUserPolicyType); | |
71 #if defined(OS_CHROMEOS) | |
72 policy_fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA); | |
73 #else | |
74 policy_fetch_request->set_signature_type(em::PolicyFetchRequest::NONE); | |
75 #endif | |
76 policy_response_.mutable_policy_response()->add_response()->set_policy_data( | |
77 CreatePolicyData("fake-policy-data")); | |
78 | |
79 unregistration_request_.mutable_unregister_request(); | |
80 unregistration_response_.mutable_unregister_response(); | |
81 } | |
82 | |
83 virtual void SetUp() OVERRIDE { | |
84 EXPECT_CALL(status_provider_, GetDeviceStatus(_)) | |
85 .WillRepeatedly(Return(false)); | |
86 EXPECT_CALL(status_provider_, GetSessionStatus(_)) | |
87 .WillRepeatedly(Return(false)); | |
88 CreateClient(USER_AFFILIATION_NONE); | |
89 } | |
90 | |
91 virtual void TearDown() OVERRIDE { | |
92 client_->RemoveObserver(&observer_); | |
93 } | |
94 | |
95 void Register() { | |
96 EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); | |
97 client_->SetupRegistration(kDMToken, client_id_); | |
98 } | |
99 | |
100 void CreateClient(UserAffiliation user_affiliation) { | |
101 if (client_.get()) | |
102 client_->RemoveObserver(&observer_); | |
103 | |
104 client_.reset(new CloudPolicyClient(kMachineID, kMachineModel, | |
105 user_affiliation, &status_provider_, | |
106 &service_)); | |
107 client_->AddNamespaceToFetch(policy_ns_key_); | |
108 client_->AddObserver(&observer_); | |
109 } | |
110 | |
111 void ExpectRegistration(const std::string& oauth_token) { | |
112 EXPECT_CALL(service_, | |
113 CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION)) | |
114 .WillOnce(service_.SucceedJob(registration_response_)); | |
115 EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestRegister, | |
116 "", oauth_token, "", "", _, | |
117 MatchProto(registration_request_))) | |
118 .WillOnce(SaveArg<5>(&client_id_)); | |
119 } | |
120 | |
121 void ExpectPolicyFetch(const std::string& dm_token, | |
122 const std::string& user_affiliation) { | |
123 EXPECT_CALL(service_, | |
124 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
125 .WillOnce(service_.SucceedJob(policy_response_)); | |
126 EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestPolicy, | |
127 "", "", dm_token, user_affiliation, | |
128 client_id_, | |
129 MatchProto(policy_request_))); | |
130 } | |
131 | |
132 void ExpectUnregistration(const std::string& dm_token) { | |
133 EXPECT_CALL(service_, | |
134 CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION)) | |
135 .WillOnce(service_.SucceedJob(unregistration_response_)); | |
136 EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestUnregister, | |
137 "", "", dm_token, "", client_id_, | |
138 MatchProto(unregistration_request_))); | |
139 } | |
140 | |
141 void CheckPolicyResponse() { | |
142 ASSERT_TRUE(client_->GetPolicyFor(policy_ns_key_)); | |
143 EXPECT_THAT(*client_->GetPolicyFor(policy_ns_key_), | |
144 MatchProto(policy_response_.policy_response().response(0))); | |
145 } | |
146 | |
147 std::string CreatePolicyData(const std::string& policy_value) { | |
148 em::PolicyData policy_data; | |
149 policy_data.set_policy_type(dm_protocol::kChromeUserPolicyType); | |
150 policy_data.set_policy_value(policy_value); | |
151 return policy_data.SerializeAsString(); | |
152 } | |
153 | |
154 // Request protobufs used as expectations for the client requests. | |
155 em::DeviceManagementRequest registration_request_; | |
156 em::DeviceManagementRequest policy_request_; | |
157 em::DeviceManagementRequest unregistration_request_; | |
158 | |
159 // Protobufs used in successful responses. | |
160 em::DeviceManagementResponse registration_response_; | |
161 em::DeviceManagementResponse policy_response_; | |
162 em::DeviceManagementResponse unregistration_response_; | |
163 | |
164 std::string client_id_; | |
165 PolicyNamespaceKey policy_ns_key_; | |
166 MockDeviceManagementService service_; | |
167 StrictMock<MockStatusProvider> status_provider_; | |
168 StrictMock<MockCloudPolicyClientObserver> observer_; | |
169 scoped_ptr<CloudPolicyClient> client_; | |
170 }; | |
171 | |
172 TEST_F(CloudPolicyClientTest, Init) { | |
173 EXPECT_CALL(service_, CreateJob(_)).Times(0); | |
174 EXPECT_FALSE(client_->is_registered()); | |
175 EXPECT_FALSE(client_->GetPolicyFor(policy_ns_key_)); | |
176 } | |
177 | |
178 TEST_F(CloudPolicyClientTest, SetupRegistrationAndPolicyFetch) { | |
179 EXPECT_CALL(service_, CreateJob(_)).Times(0); | |
180 EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); | |
181 client_->SetupRegistration(kDMToken, client_id_); | |
182 EXPECT_TRUE(client_->is_registered()); | |
183 EXPECT_FALSE(client_->GetPolicyFor(policy_ns_key_)); | |
184 | |
185 ExpectPolicyFetch(kDMToken, dm_protocol::kValueUserAffiliationNone); | |
186 EXPECT_CALL(observer_, OnPolicyFetched(_)); | |
187 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()); | |
188 client_->FetchPolicy(); | |
189 EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); | |
190 CheckPolicyResponse(); | |
191 } | |
192 | |
193 TEST_F(CloudPolicyClientTest, RegistrationAndPolicyFetch) { | |
194 ExpectRegistration(kOAuthToken); | |
195 EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); | |
196 client_->Register(em::DeviceRegisterRequest::USER, | |
197 kOAuthToken, std::string(), false); | |
198 EXPECT_TRUE(client_->is_registered()); | |
199 EXPECT_FALSE(client_->GetPolicyFor(policy_ns_key_)); | |
200 EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); | |
201 | |
202 ExpectPolicyFetch(kDMToken, dm_protocol::kValueUserAffiliationNone); | |
203 EXPECT_CALL(observer_, OnPolicyFetched(_)); | |
204 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()); | |
205 client_->FetchPolicy(); | |
206 EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); | |
207 CheckPolicyResponse(); | |
208 } | |
209 | |
210 TEST_F(CloudPolicyClientTest, RegistrationParameters) { | |
211 registration_request_.mutable_register_request()->set_reregister(true); | |
212 registration_request_.mutable_register_request()->set_auto_enrolled(true); | |
213 ExpectRegistration(kOAuthToken); | |
214 EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); | |
215 client_->Register(em::DeviceRegisterRequest::USER, | |
216 kOAuthToken, kClientID, true); | |
217 EXPECT_EQ(kClientID, client_id_); | |
218 } | |
219 | |
220 TEST_F(CloudPolicyClientTest, RegistrationNoToken) { | |
221 registration_response_.mutable_register_response()-> | |
222 clear_device_management_token(); | |
223 ExpectRegistration(kOAuthToken); | |
224 EXPECT_CALL(observer_, OnClientError(_)); | |
225 client_->Register(em::DeviceRegisterRequest::USER, | |
226 kOAuthToken, std::string(), false); | |
227 EXPECT_FALSE(client_->is_registered()); | |
228 EXPECT_FALSE(client_->GetPolicyFor(policy_ns_key_)); | |
229 EXPECT_EQ(DM_STATUS_RESPONSE_DECODING_ERROR, client_->status()); | |
230 } | |
231 | |
232 TEST_F(CloudPolicyClientTest, RegistrationFailure) { | |
233 EXPECT_CALL(service_, | |
234 CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION)) | |
235 .WillOnce(service_.FailJob(DM_STATUS_REQUEST_FAILED)); | |
236 EXPECT_CALL(service_, StartJob(_, _, _, _, _, _, _)); | |
237 EXPECT_CALL(observer_, OnClientError(_)); | |
238 client_->Register(em::DeviceRegisterRequest::USER, | |
239 kOAuthToken, std::string(), false); | |
240 EXPECT_FALSE(client_->is_registered()); | |
241 EXPECT_FALSE(client_->GetPolicyFor(policy_ns_key_)); | |
242 EXPECT_EQ(DM_STATUS_REQUEST_FAILED, client_->status()); | |
243 } | |
244 | |
245 TEST_F(CloudPolicyClientTest, RetryRegistration) { | |
246 // First registration does not set the re-register flag. | |
247 EXPECT_FALSE( | |
248 registration_request_.mutable_register_request()->has_reregister()); | |
249 MockDeviceManagementJob* register_job = NULL; | |
250 EXPECT_CALL(service_, | |
251 CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION)) | |
252 .WillOnce(service_.CreateAsyncJob(®ister_job)); | |
253 EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestRegister, | |
254 "", kOAuthToken, "", "", _, | |
255 MatchProto(registration_request_))); | |
256 client_->Register(em::DeviceRegisterRequest::USER, | |
257 kOAuthToken, std::string(), false); | |
258 EXPECT_FALSE(client_->is_registered()); | |
259 Mock::VerifyAndClearExpectations(&service_); | |
260 | |
261 // Simulate a retry callback before proceeding; the re-register flag is set. | |
262 registration_request_.mutable_register_request()->set_reregister(true); | |
263 EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestRegister, | |
264 "", kOAuthToken, "", "", _, | |
265 MatchProto(registration_request_))); | |
266 register_job->RetryJob(); | |
267 Mock::VerifyAndClearExpectations(&service_); | |
268 | |
269 // Subsequent retries keep the flag set. | |
270 EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestRegister, | |
271 "", kOAuthToken, "", "", _, | |
272 MatchProto(registration_request_))); | |
273 register_job->RetryJob(); | |
274 Mock::VerifyAndClearExpectations(&service_); | |
275 } | |
276 | |
277 TEST_F(CloudPolicyClientTest, PolicyUpdate) { | |
278 Register(); | |
279 | |
280 ExpectPolicyFetch(kDMToken, dm_protocol::kValueUserAffiliationNone); | |
281 EXPECT_CALL(observer_, OnPolicyFetched(_)); | |
282 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()); | |
283 client_->FetchPolicy(); | |
284 CheckPolicyResponse(); | |
285 | |
286 policy_response_.mutable_policy_response()->clear_response(); | |
287 policy_response_.mutable_policy_response()->add_response()->set_policy_data( | |
288 CreatePolicyData("updated-fake-policy-data")); | |
289 ExpectPolicyFetch(kDMToken, dm_protocol::kValueUserAffiliationNone); | |
290 EXPECT_CALL(observer_, OnPolicyFetched(_)); | |
291 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()); | |
292 client_->FetchPolicy(); | |
293 EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); | |
294 CheckPolicyResponse(); | |
295 } | |
296 | |
297 TEST_F(CloudPolicyClientTest, PolicyFetchWithMetaData) { | |
298 Register(); | |
299 | |
300 const base::Time timestamp( | |
301 base::Time::UnixEpoch() + base::TimeDelta::FromDays(20)); | |
302 client_->set_submit_machine_id(true); | |
303 client_->set_last_policy_timestamp(timestamp); | |
304 client_->set_public_key_version(42); | |
305 em::PolicyFetchRequest* policy_fetch_request = | |
306 policy_request_.mutable_policy_request()->mutable_request(0); | |
307 policy_fetch_request->set_machine_id(kMachineID); | |
308 policy_fetch_request->set_timestamp( | |
309 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); | |
310 policy_fetch_request->set_public_key_version(42); | |
311 | |
312 ExpectPolicyFetch(kDMToken, dm_protocol::kValueUserAffiliationNone); | |
313 EXPECT_CALL(observer_, OnPolicyFetched(_)); | |
314 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()); | |
315 client_->FetchPolicy(); | |
316 CheckPolicyResponse(); | |
317 } | |
318 | |
319 TEST_F(CloudPolicyClientTest, BadPolicyResponse) { | |
320 Register(); | |
321 | |
322 policy_response_.clear_policy_response(); | |
323 ExpectPolicyFetch(kDMToken, dm_protocol::kValueUserAffiliationNone); | |
324 EXPECT_CALL(observer_, OnClientError(_)); | |
325 client_->FetchPolicy(); | |
326 EXPECT_FALSE(client_->GetPolicyFor(policy_ns_key_)); | |
327 EXPECT_EQ(DM_STATUS_RESPONSE_DECODING_ERROR, client_->status()); | |
328 | |
329 policy_response_.mutable_policy_response()->add_response()->set_policy_data( | |
330 CreatePolicyData("fake-policy-data")); | |
331 policy_response_.mutable_policy_response()->add_response()->set_policy_data( | |
332 CreatePolicyData("excess-fake-policy-data")); | |
333 ExpectPolicyFetch(kDMToken, dm_protocol::kValueUserAffiliationNone); | |
334 EXPECT_CALL(observer_, OnPolicyFetched(_)); | |
335 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()); | |
336 client_->FetchPolicy(); | |
337 EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); | |
338 CheckPolicyResponse(); | |
339 } | |
340 | |
341 TEST_F(CloudPolicyClientTest, PolicyRequestFailure) { | |
342 Register(); | |
343 | |
344 EXPECT_CALL(service_, | |
345 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
346 .WillOnce(service_.FailJob(DM_STATUS_REQUEST_FAILED)); | |
347 EXPECT_CALL(service_, StartJob(_, _, _, _, _, _, _)); | |
348 EXPECT_CALL(observer_, OnClientError(_)); | |
349 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()).Times(0); | |
350 client_->FetchPolicy(); | |
351 EXPECT_EQ(DM_STATUS_REQUEST_FAILED, client_->status()); | |
352 EXPECT_FALSE(client_->GetPolicyFor(policy_ns_key_)); | |
353 } | |
354 | |
355 TEST_F(CloudPolicyClientTest, Unregister) { | |
356 Register(); | |
357 | |
358 ExpectUnregistration(kDMToken); | |
359 EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); | |
360 client_->Unregister(); | |
361 EXPECT_FALSE(client_->is_registered()); | |
362 EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); | |
363 } | |
364 | |
365 TEST_F(CloudPolicyClientTest, UnregisterEmpty) { | |
366 Register(); | |
367 | |
368 unregistration_response_.clear_unregister_response(); | |
369 EXPECT_CALL(service_, | |
370 CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION)) | |
371 .WillOnce(service_.SucceedJob(unregistration_response_)); | |
372 EXPECT_CALL(service_, StartJob(_, _, _, _, _, _, _)); | |
373 EXPECT_CALL(observer_, OnRegistrationStateChanged(_)); | |
374 client_->Unregister(); | |
375 EXPECT_FALSE(client_->is_registered()); | |
376 EXPECT_EQ(DM_STATUS_SUCCESS, client_->status()); | |
377 } | |
378 | |
379 TEST_F(CloudPolicyClientTest, UnregisterFailure) { | |
380 Register(); | |
381 | |
382 EXPECT_CALL(service_, | |
383 CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION)) | |
384 .WillOnce(service_.FailJob(DM_STATUS_REQUEST_FAILED)); | |
385 EXPECT_CALL(service_, StartJob(_, _, _, _, _, _, _)); | |
386 EXPECT_CALL(observer_, OnClientError(_)); | |
387 client_->Unregister(); | |
388 EXPECT_TRUE(client_->is_registered()); | |
389 EXPECT_EQ(DM_STATUS_REQUEST_FAILED, client_->status()); | |
390 } | |
391 | |
392 TEST_F(CloudPolicyClientTest, PolicyFetchWithExtensionPolicy) { | |
393 Register(); | |
394 | |
395 // Setup the |expected_responses| and |policy_response_|. | |
396 static const char* kExtensions[] = { | |
397 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | |
398 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", | |
399 "cccccccccccccccccccccccccccccccc", | |
400 }; | |
401 typedef std::map<PolicyNamespaceKey, em::PolicyFetchResponse> ResponseMap; | |
402 ResponseMap expected_responses; | |
403 std::set<PolicyNamespaceKey> expected_namespaces; | |
404 PolicyNamespaceKey key(dm_protocol::kChromeUserPolicyType, std::string()); | |
405 // Copy the user policy fetch request. | |
406 expected_responses[key].CopyFrom( | |
407 policy_response_.policy_response().response(0)); | |
408 expected_namespaces.insert(key); | |
409 key.first = dm_protocol::kChromeExtensionPolicyType; | |
410 for (size_t i = 0; i < arraysize(kExtensions); ++i) { | |
411 key.second = kExtensions[i]; | |
412 em::PolicyData policy_data; | |
413 policy_data.set_policy_type(key.first); | |
414 policy_data.set_settings_entity_id(key.second); | |
415 expected_responses[key].set_policy_data(policy_data.SerializeAsString()); | |
416 policy_response_.mutable_policy_response()->add_response()->CopyFrom( | |
417 expected_responses[key]); | |
418 expected_namespaces.insert(key); | |
419 } | |
420 | |
421 // Make a policy fetch. | |
422 EXPECT_CALL(service_, | |
423 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)) | |
424 .WillOnce(service_.SucceedJob(policy_response_)); | |
425 EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestPolicy, "", "", | |
426 kDMToken, | |
427 dm_protocol::kValueUserAffiliationNone, | |
428 client_id_, _)) | |
429 .WillOnce(SaveArg<6>(&policy_request_)); | |
430 EXPECT_CALL(observer_, OnPolicyFetched(_)); | |
431 EXPECT_CALL(status_provider_, OnSubmittedSuccessfully()); | |
432 for (size_t i = 0; i < arraysize(kExtensions); ++i) { | |
433 client_->AddNamespaceToFetch(PolicyNamespaceKey( | |
434 dm_protocol::kChromeExtensionPolicyType, kExtensions[i])); | |
435 } | |
436 client_->FetchPolicy(); | |
437 | |
438 // Verify that the request includes the expected namespaces. | |
439 ASSERT_TRUE(policy_request_.has_policy_request()); | |
440 const em::DevicePolicyRequest& policy_request = | |
441 policy_request_.policy_request(); | |
442 ASSERT_EQ(static_cast<int>(1 + arraysize(kExtensions)), | |
443 policy_request.request_size()); | |
444 for (int i = 0; i < policy_request.request_size(); ++i) { | |
445 const em::PolicyFetchRequest& fetch_request = policy_request.request(i); | |
446 ASSERT_TRUE(fetch_request.has_policy_type()); | |
447 std::string entity_id; | |
448 if (fetch_request.has_settings_entity_id()) | |
449 entity_id = fetch_request.settings_entity_id(); | |
450 PolicyNamespaceKey key(fetch_request.policy_type(), entity_id); | |
451 EXPECT_EQ(1u, expected_namespaces.erase(key)); | |
452 } | |
453 EXPECT_TRUE(expected_namespaces.empty()); | |
454 | |
455 // Verify that the client got all the responses mapped to their namespaces. | |
456 for (ResponseMap::iterator it = expected_responses.begin(); | |
457 it != expected_responses.end(); ++it) { | |
458 const em::PolicyFetchResponse* response = client_->GetPolicyFor(it->first); | |
459 ASSERT_TRUE(response); | |
460 EXPECT_EQ(it->second.SerializeAsString(), response->SerializeAsString()); | |
461 } | |
462 } | |
463 | |
464 } // namespace policy | |
OLD | NEW |